Linux İleri Seviye Kullanıcılar


LİNUXTA KULLANICI VE GRUP
KULLANICILAR VE SİSTEME LOGİN OLMA
    Bir Linux sistemine her erişim bir kullanıcı hesabı yoluyla olur. Her kullanıcı hesabı da sistem administarator'u tarafından oluşturulup hakları düzenlenmiştir. root olarak adlandırılan bu en güçlü account diğer kullanıcıların hesaplarını düzenlediği için dosya, dizin, kullanıcı ve grup haklarının nasıl ayarlanacağını iyi bilmek gereklidir. Biraz root account'undan bahsedeyim..

    Bir Linux sürümü kurulduktan sonra otomatik olarak bir master login yaratılır ve tahmin edeceğiniz gibi 'root' olarak adlandırılır. Bu kullanıcı hesabı süper kullanıcı olarak adlandırılır çünkü bu kullanıcı hesabının erişemeyeceği hiçbir alan yoktur( tabiki kendi sisteminin içinde ..). Sisteme root olarak girdiğinizde dosya izinlerinden, erişim haklarından ya da yazılıım ayarlarından hiç çekinmenizie gerek yoktur. Çünkü bu hakla bir komutla sistemi çalışamaz hale getirebilecek kadar hakkınız vardır. Bu yüzden kendinize root dan başka bir hesap açıp her zaman bu hesabı kullanmanız ve sadece gerekli olduğu taktirde root hesabını kullanmanız önerilir. Hatta çok kullanıcılı bir sisteme sahipseniz root şifresini düzenli olarak kısa aralıklarla değiştirmeniz de önerilir.
    Önemli bir nokta da bu otomatik olarak yaratılan süperkullanıcı hesabının ismi 'root' olmak zorunda değildir. Teorik olarak bu hesap herhengi bir ismi taşıyabilir, ancak genelde root olarak kullanılır. Süperkullanıcı olmanın sistemde tanımı /etc/passwd dosyasındaki user ID nin 0 (sıfır) olmasında saklıdır. Yani şunu da söyleyeyim user ID sini 0 verdiğiniz bir diğer kullanıcı da superkullanıcının haklarına sahip olacaktır...
KULLANICI HESAPLARI
    Bir sistemin tek kullanıcısı bile olsanız kullanıcı yaratmayı ve haklarını düzenlemeyi bilmelisiniz. Çünkü en azından önerilenleri yerine getirirseniz günlük kullanım için root dan başka bir hesap yaratmanız gerekmektedir. Şayet sisteminize direk olarak ya da modemle erişecek başkaları da varsa o zaman herbiri için bir hesap açmanız gerekecektir. Bu nedenle bu konuya hakim olmanız gerekmektedir.
    Sisteminizi kullanacak herkesin diğerlerinden ayrı bir kullanıcı adı ve şifresi olacaktır. Bazen istisnalar olabilir, yani bir database' e sadece read only erişen programın kullanabileceği guest ya da benzeri bir kullanıcıya ihtiyaç olabilir. Aksi durumda ilk hal geçerlidir. Her kullanıcının kullanıcı isminin farklı olması sistemin güvenliğini arttıracaktır. Mesela siz o anda kimlerin sistemde olduğunu ve ne işler yaptığını izleyebileceksiniz.
    /etc/passwd dosyası kullanıcılar hakkında her bilgiyi içermektedir. Bu dosyanın sahibi root olmalıdır ve group ID olarak da root'un group numarası olan 0 (sıfır) verilmelidir. Biraz ayrıntıya girelim, ve bu dosyanın mantığını anlamaya çalışalım. Bu dosydaki her satır bir kullanıcının bilgisini belirli bir düzende saklar..
username : passwd : user ID : comment : home directory : login command
Bu dizimi anlayabilmek için yeni kurulmuş bir sistemin /etc/passwd dosyasına bir göz atalım:
root::0:0:root:/root:/bin/bash
bin:*:1:1:bin:/bin:
daemon:*:2:2:daemon:/sbin:
adm:*:3:4:adm:/var/adm:
lp:*:4:7:lp:/var/spool/lpd:
sync:*:5:0:sync:/sbin:/bin/sync
shutdown:*:6:0:shutdown:/sbin:/sbin/shutdown
halt:*:7:0:halt:/sbin:/sbin/halt
mail:*:8:12:mail:/var/spool/mail:
news:*:9:13:news:/usr/lib/news:
uucp:*:10:14:uucp:/var/spool/uucppublic:
operator:*:11:0:operator:/root:/bin/bash
games:*:12:100:games:/usr/games:
man:*:13:15:man:/usr/man:
postmaster:*:14:12:postmaster:/var/spool/mail:/bin/bash
nobody:*:-1:100:nobody:/dev/null:
ftp:*:404:1::/home/ftp:/bin/bash
    Bu dosyadaki her satır birbirinden ' : ' ile ayrılmış yedi alandan oluşur. Eğer bu alanların herhangi birine hiçbir bilgi girilmez ise o zaman bu alan boş bırakılır ama yine de ' : ' ile ona ayrılan yeri iptal edilmeden kullanılır. Sırayla bu yedi kolona bakalım:
    username              kullanıcının diğerlerinden farklı olan tanımlayıcı ismi
   
 password               kullanıcının şifresi (encript edilmiş durumdadır)
    
user ID                   kullanıcıyı sisteme tanımlayan ve diğerlerinden farklı olan bir rakam
    
group ID              dosya izinleri için kullanıcının grubunu belirler
    
comment              genelde kullanıcının gerçek ismi yazılır ama bazen de telefon numarası bölüm  ya da benzeri bilgiler yazılır
  
  home directory       kullanıcı sisteme girince bulunacaği ve tüm dosyalarını saklayacağı ev dizini
   
 login command      kullanıcı sisteme girdikten sonra işletilecek komut. genelde bir shell başlatan
komut olmasına rağmen istendiğinde kullanıcının sadece mail programı kullanması istenirse buraya programı işleten komut yazılabilir.
KULLANICI HESABI OLUŞTURMAK
   En genel olarak bir kullanıcı eklemek için gerekli dosyaya bir satırlık bilgi eklemek gerekmektedir. Eğer hangi sistemin hangi dosyada kullanıcı bilgilerini tuttuğunu bilirseniz sadece bu dosyada değişikilik yaparak kullanıcı ekler ya da çıkartabilirsiniz. Normalde kullanıcı eklemek için bazı scripler mevcuttur. Örneğin Slackware Linuxta adduser isimli bir script yaratılacak kullanıcının bilgilerini teker teker alarak bunları uygun şekilde /etc/passwd dosyasına yazar. Redhat gibi diğer sistemlerde de adduser ya da useradd komutları vardır ancak bunları parametreleriyle beraber kullanmadan bir iş yapmazlar. Yani demek istediğim sadece bir satır yazıyı ilgili dosyaya yazarak ve kullanıcıya bir dizin oluşturarak bir kullanıcı yaratabiliriz. Bu sayede en genelini öğrenmiş oluruz. /etc/passwddosyasına ekleme yapmak için istediğiniz bir editörü kullanabilirsiniz. pico, vi , jed hatta mc kullanarak bile dosyayı değiştirebilirsiniz. Mesela şu satırı ekleyerek sisteme student diye bir kullanıcı ekleyelim :
student::103:50:studnet in school:/home/student:/bin/sh
    Burada dikkat edilmesi gereken kullanıcı isminin diğerlerinden ayrı olması, User ID nin bir öncekini takip etmesi (yine diğerlerinden ayrı olan) , Group ID olarak da 50 (default group) verilmesi (bu şart olmamasına rağmen ileride değişiklik yapılabilir ya da bilinen bir grubun numarası verilebilir), bir kullanıcı ev dizini belirtilmesi ve de sisteme girince kullanacağı shell'in seçilmesi.
    Sanırım şifre kısmının boş olduğunu farketmişsinizdir. Encritp edilmiş bir şifreyi siz yazamayacağınız için burayı boş bırakmalısınız. Yaptığınız değişiklikleri kaydettikten sonra bu yeni hesaba bir şifre verebilirsiniz. Verdiğiniz şifre doğrultusunda encript edilmiş bilgi /etc/passwd dosyasına yazılacaktır. Bunu yapmak için de
# passwd student
yazın ve onaylayarak bir şifre sağlayın. Bundan sonra da studnet kullanıcısının ev dizinini oluşturmanız gerekmektedir. Ardından da bu dizinin sahibini student olarak atamalıyız. Sırasıyla şu komutları işletin:
# mkdir /home/student
#chown student /home/student
    ilk komutla /home/student dizini yaratılır. Ancak root olarak bu yaratıldığı için sahibi de root dur. Bu yüzden bunun sahibini değiştirmek için ikinci satırı kullandık. Yani /home/student dizininin sahibini student olarak değiştir dedik.
    Buraya kadar bir kullanıcı hesabı yaratmayı öğrendik. Şimdi de artık sisteminizde bulunmasını istemediğiniz bir kullanıcının hesabını nasıl sileceğimize bakalım.
BİR KULLANICI HESABINI SİLMEK
    Aynen kullanıcı eklemede olduğu gibi bazı sistemlerde otomatik olarak kullanıcı silen scriptler mevcuttur. Bu scriptler size hangi kullanıcıyı silmek istediğinizi sorarlar ve sizin verdiğiniz yanıta göre bu kullanıcıyı /etc/passwddosyasından bulup dosyadaki bu satırı silerler.
    Bir kullanıcıyı manuel olarak silmek için aynı şeyi yapmalıyız. /etc/passwd dosyasından ilgili kullanıcının bulunduğu satırı silmeliyiz. Şayet bir kullanıcının hesabını bir sure kaldırmak istiyorsanız sadece /etc/passwd dosyasındaki isminin bulunduğu satırın başına bir diyez karakteri koyabilirsiniz. Bu sayede o kullanıcının sisteme siz izin verene kadar girmesini engellersiniz.
    Eğer sildiğiniz kullanıcının bir daha sisteme eklenme ihtimali yok ise o zaman o kullanıcının dizinlerini de silmelisiniz. Böylece disk tasarrufu yaparsınız. Bir komut ile bu dizini ve altdizinlerini silemek için
# rm -r /home/userdir
    komutunu kullanın. Dikkat edin /home/userdir diye yazılan kullanıcının gerçek dizininin yolu olmalıdır. Yoksa başka dizinleri de silebilirsiniz.
    Daha sonra kullanıcının mail spool dosyasını silin. Genellikle bu dosya /usr/spool/mail/username olarak saklanır. Deminki gibi
# rm /usr/spool/mail/student
komutunu işletirseniz student kullanıcısının mail spool dosyasını silersiniz. Norton Commander kullanmaya alışık olanlar aynı işlemleri mc ile de yapabilirsiniz. Mail temizlemesini bitirmek için kullanıcının /usr/lib/aliases dosyasında bir aliasının olmamasına dikkat edin. Eğer varsa bunu da kaldırın.
GRUPLARI KULLANMAK
    Her Unix sisteminde olduğu gibi her Linux sisteminde de bütün kullanıcılar birer gruba üyedirler. Aynı gruptaki her kullanıcı aynı departmanda çalıştığını varsayın. Bu çalışanların ortak olarak erişmesi gereken datalar ya da aygıtlar olabilir. Mesela baskı bölümünün üyelerinin bulunduğu gruba renkli yazıcıyı kullanma hakkı vermek gibi. Gruplar dosya erişim haklarını ayarlamada kullanıldıkları için bir kullanıcı en az bir gruba üye olmalıdır.
    Genelde küçük sistemler bir tane default gruba sahiptirler. Çünkü bu sistem yönetimini oldukça basitleştirir. Bu durumda her kullanıcının bir aygıta ya da dosyaya erişimi o aygıtların ya da dosyaların kendi erişim haklarına göre sağlanır.
    Grup bilgisi /etc/group dosyasında saklanmaktadır. Bu dosya da aynı /etc/passwd dosyasında olduğu gibi bir dizime sahiptir. Örneğin yeni kurulmuş bir Linux sisteminin defauld /etc/group dosyası aşağıdakine çok benzerdir.
root::0:root
bin::1:root,bin,daemon
daemon::2:root,bin,daemon
sys::3:root,bin,adm
adm::4:root,adm,daemon
tty::5:
disk::6:root,adm
lp::7:lp
mem::8:
kmem::9:
wheel::10:root
floppy::11:root
mail::12:mail
news::13:news
uucp::14:uucp
man::15:man
users::100:games
nogroup::-1:
Burada da her satır birbirinden : ile ayrılmış dört alandan oluşmuştur ve formatı da şöyledir :
group name : group passwd : group ID : users
    Bu dosya içinde her grubun kendine ait bir satırı vardır. Her Linux sisteminin işletim sistemine ait olan birkaç tane grubu vardır. Bu gruplar bin, mail, uucp, sys, ....gibidir. Biraz da sistem gruplarını inceleyelim.
root/wheel/system grubu bir kullanıcının su komutuyla root erişimine izin vermek içindir.deamon grubu spooling dizinlerinin(mail, printer gibi) sahipliklerini sağlar.kmem grubu programların kernel hafızasına direct erişim içindir.sys grubu bazı sistem dosyalarını sahiplenmek içindir. Bazı sistemlerde kmem gibi davranır.tty grubu terminallerle alakalı bütün özel dosyaların sahipliği içindir.
GRUP EKLEMEK
    Bir grup eklemek için /etc/group dosyasında değişiklikler yapmanız gereklidir. Herhangi bir ASCII editör kullanarak bunu halledebilirsiniz. Ya da groupadd gibi önceden yazılmış scriptleri kullanabilirsiniz. Sonuçta yapılan iş aynıdır. Tabiki her versiyonda bu otomatiklik scriptleri mevcut değildir. Bu yüzden tam olarak yapılması gerekeni öğrenmek en iyisidir. Yeni gruplar eklemeden önce eski dosyanın bir yedeğini almanızı tavsiye ederim. Aksilik halinde geri dönebilmek için faydalı olacaktır. Mesela iki yeni grup eklemek için aşağıdaki satırları /etc/groupsdosyasına ekleyin
hesap::51:student
printer::52:teacher
bunları yazıp değişiklikleri kaydettikten sonra gruplar eklenmiş olacaktır. Bir kullanıcının birden fazla gruba üye olabilmesi için kullanıcı ismini ilgili gubun yanına aralarına virgül koyarak yazabiliriz.
hesap::51:student , teacher
printer::52:teacher
    Burada student ve tezcher aynı grubun üyeleridir. Burada aynı gruba ait kullanıcıların sınırı yoktur. Dilediğiniz kadar kullanıcıyı bir gruba dahil edebilirsiniz.
    Kullanıcı aynı anda sadece bir gruba dahil olabilir. Şayet kullanıcı bir başka gruba da üye ise o gruba dahil olmak için komut satırında
# newgrp
komutunu kullanarak üye olduğu gruplardan bir diğerine girebilir.
GRUP SİLMEK
    Eğer bir grubun artık ortadan kalkmasını istiyorsanız o zaman grubun bulunduğu satırı /etc/group dosyasından kaldırmanız yeterli olacaktır. Bunu silmeden önce /etc/passwd dosyasını kontrol edin ve bu grubun mensubları olan kullanıcıların başlangıç grubu olarak bu silinen grup olmamasına özen gösterin. Eğer bunu yapmayı unutursanız ve bir kullanıcının sisteme girdiğinde dahil olması gereken grup ortada yoksa bu kullanıcı sisteme giremeyecektir. Aynı şekilde bütün dosya ve dizinleri kontrol edip bunların silinen grubun sahipliğinde olup olmadığına bakmalısınız. Eğer varsa bunları başka grupla değiştirmelisiniz.
su KOMUTUNU KULLANMAK



 
    Bazen normal kullanıcı hesabınızı kullanırken root olarak yapabileceğiniz işler vardır. İşte bu zaman su komutuyla çabucak root hakkına ulaşabilirsiniz. Bunu kullanmak yerine ya yeni bir terminalden tekrar login olup root olarak sisteme girmelisiniz ve işiniz bitince bu terminalden logout olup tekrar eski terminalinize dönmelisiniz. İşte bu işi sadece su komutuyla halledebilirsiniz.
    Bir başka kullanıcının hesabını kullanmak isterseniz yine su komutuyla
# su student
yazabilirsiniz. Eğer sadece su yazarsanız o zaman root olmak istediğinizi sanıp sizden root şifresini ister.

UNIX OLANAKLARI
İŞLEMLER, KOMUT GİRME, YÖNLENDİRME,
İŞLEMLER ARASI İLETİŞİM

UNIX ORTAMI
UNIX özet olarak bellekte çalışan çekirdek bir işletim sistemi (kernel) ve bu program tarafından başlatılan diğer işlemlerden (programlardan) oluşur. Kavram olarak UNIX için her şey bir kütüktür. Ana bellek, disk, terminallerin bağlandığı seri uçlar, disket sürücü, yazıcı bağlantısı, CD sürücü ve diğerleri hepsi bir kütük olarak tanımlıdır.
UNIX ortamında bir kütük, en az bir byte okunabilen ve/veya yazılabilen birime verilen addır. Bir kütüğü açmak, kütükten okumak, kütüğe yazmak ve kütüğü kapatmak için kullanılan komutların tümüne sürücü program adı verilir. Sürücü program (driver), ya çekirdek işletim sistemi içine gömülüdür, ya da işletim sistemi tarafından bilgisayar açıldığında belleğe yüklenir.
UNIX işletim sistemi ilk çalıştığında sürücü programları yükledikten, çevre birimlerini tanıdıktan sonra kök kütük yapısını (root file sistem) sisteme bağlar ve bu yapı içinden init adlı programı çalıştırır. init UNIX ortamında çalışan ilk işlem olduğu için işlem numarası 1 dir. UNIX bellekteki her işlemi tekil bir numara ile izler. Bu işlemi başlatmak, durdurmak UNIX tarafından bilinen işlem numarası aracılığı ile yapılır. init öncestdinstdout ve stderr kütüklerini açar. Bu kütüklerin kullanım hakkı init tarafından başlatılan tüm programlara devredilir. init kök kütük yapısındaki programları başlatmak için /etc/inittab kütüğünü okur. Burada hangi programların ne zaman başlatılacağı bilgisi vardır. Bir program, sistem ilk açıldığında, tek kullanıcılı ortamda veya çok kullanıcılı ortamda çalışabilir. Sistem açıldığında ve tek kullanıcılı ortamda çalıştırılan programlar çoğunlukla çevre birimi sürücü programları, iletişim protokolu programları olur. Çok kullanıcılı ortamda başlatılan programlar ise kullanıcıların terminallerinden ve modemlerden sisteme girişlerine olanak veren programlardır.
Aşağıdaki örnek, bir inittab kütüğünün içeriğinde bulunan bilgileri gösterir. Burada her işlem satırındaki bilgilerin anlamı kısaca şöyle açıklanabilir. Birinci bilgi alanı işlem adımının adıdır. İkinci alan, işlemin, sistemin hangi çalışma düzeyinde, çalışması gerektiğini belirtir. Çalışma düzeyleri 0-6 arasında bir değerdir. Üçüncü alan işlemin hangi konumda olması gerektiğini gösterir (respawn, wait, off gibi). Dördüncü alan ise çalışacak işlemin kök kütük yapısındaki yerini tanımlar.
/etc/inittab

#
# inittab INIT işleminin nasıl çalışacağını gösteren kütüktür
#
# # Default çalışma düzeyi.
id:3:initdefault:

# sistem başlama zamanı (sistem boot olurken çalışır).
si:S:sysinit:/etc/rc.d/rc.S

# Tek kullanıcılı ortama geçiş için gereken komut (çalışma düzeyi 1).
su:1S:wait:/etc/rc.d/rc.K

# Çok kullanıcı ortama geçiş için gereken komut.
rc:23456:wait:/etc/rc.d/rc.M

# yeniden boot etmek için gereken işlem (Ctrl+Alt+Del).
ca::ctrlaltdel:/sbin/shutdown -t5 -rfn now

# Çalışma düzeyi 0, Sistemi durdurur (kapatır).
l0:0:wait:/etc/rc.d/rc.0

# Çalışma düzeyi 6, sistemi yeniden başlatır (reboot).
l6:6:wait:/etc/rc.d/rc.6

# Güç kaynağı kesildiğinde yapılacak işlem (Sistemi tek kullanıcılı ortama alma).
pf::powerfail:/sbin/shutdown -f +5 "THE POWER IS FAILING"

# Kapanmadan güç kaynağı gelirse, kapatma işlemini durdurma.
pg:0123456:powerokwait:/sbin/shutdown -c "THE POWER IS BACK"

# Tek kullanıcılı ortamda elektrik gerilse, çok kullanıcılı ortama geçme.
ps:S:powerokwait:/sbin/init 5

# Çok kullanıcılı ortamda sistem konsolu ve terminaller için getty işlemi.
#
c1:1235:respawn:/sbin/agetty 38400 tty1 vt100
c2:1235:respawn:/sbin/agetty 38400 tty2 vt100
c3:1235:respawn:/sbin/agetty 38400 tty3 vt100
***

# Seri uçlardan terminaller için getty işlemi
#s1:12345:respawn:/sbin/agetty 19200 ttyS0 vt100
#s2:12345:respawn:/sbin/agetty 19200 ttyS1 vt100
***

# Telefon hattına bağlı modemler için getty işlemi
d1:12345:respawn:/sbin/agetty -mt60 38400,19200,9600,2400,1200 ttyS0 vt100
d2:12345:respawn:/sbin/agetty -mt60 38400,19200,9600,2400,1200 ttyS1 vt100
***


init tarafından başlatılan programlar veya işlemlerle sistem çok kullanıcılı ortama geçer. Çok kullanıcılı ortamda sisteme bağlı terminallere login ekranı gelir. Modemler telefon çağrısını bekler konuma geçer. Varsa yerel ağ donanımı dışarıdan gelen sinyalleri algılacak komunda bekler. Sisteme başka sistemlerden giriş yapılabilmesi için kullanılan sürücü programlara (nfs, nis, inetd, lpd gibi) servis sunucu programlar veyadeamon adı verilir. Bu programlar bellekte dinleme konumunda bulunurlar ve ilk gelen bilgiye cevap verecek biçimde beklerler. Çoğu zaman yapılan ilk isteği algılar, bu isteğe cevap verebilecek programı çalıştırır ve tekrar bekleme konumuna geçerler.
Yalnız getty programının çalışma sistemi farklıdır. Burada terminal ekranına login bilgisi gönderilir ve giriş yapılması beklenir. İlk girilen bilgi ile gettylogin programını çalıştırıp bellekten silinir. Login, kullanıcı adını/etc/passwd kütüğünden kontrol eder, bilgi geçerli ise passwd programını çalıştırarak, kullanıcı şifresinin girilmesini beklemeye başlar. passwd programı geçerli şifreyi aldıktan sonra /etc/passwd kütüğündeki kütük yoluna geçiş yapar ve kullanıcı için tanımlanan işlemi, o kullanıcı adına çalıştırır. Bu işlem çoğu kez bir kabuk (shell) programıdır. Özel durumlarda ise hiç bir kabuk oluşturmadan, doğrudan uygulama programı başlatılabilir.
KABUK (SHELL) ORTAMI
Kabuk (shell), kullanıcının komut girebilmesi, girdiği komutu çalıştırabilmesi için hazırlanmış özel bir programdır. /usr/bin/sh kullanılan programın yolunu ve programın adını belirtir. Kabuk programı /etc/passwdkütüğünde belirtilen kullanıcı yolunu, o kullanıcı için UNIX kütük yapısı altında kullanıcı yurdu (HOME) olarak belirler. Burada bulunan profile adlı kütükten ilk tanımları, çevre değişkenleri değerlerini ve çalıştırması gereken programları alır ve kullanıcıya komut girmesi için komut simgesi (prompt) görüntüler.
Artık kullanıcı UNIX ortamında komut girebilir, derleme yapabilir, yetkisi ölçüsünde çalıştırabileceği her şeyi kullanır.
Kullanıcı kabuktan çıkmak için Crtl+D tuşlarına basar veya exit yazar. Terminal tekrar init programı kontroluna geçer. init programı /etc/inittab kütüğünden bu terminal için çalıştırcağı programı bulur (bu getty adlı programdır) ve onu çalıştırır. getty ekrana login bilgisini görüntüler ve bilgi girişi yapılmasını bekler.
UNIX ortamında işletim sistemine bir işlem yaptırmak için kullanıcının sisteme girmesi, kendi kabuk programı altından ilgili komutu çalıştırması gerekir. UNIX ortamında çalıştırılan bir program, kullanıcının ve kullanıcının bağlı olduğu grubun sistem kullanma olanakları ve yetkileri ile sınırlıdır. Teorik olarak her kullanıcı, her işlemi çalıştıramaz, başlattığı her işlemde her işi yaptıramaz.
Özetlemek gerekirse bir işlem, UNIX altında çalışan bir programdır. Her programı başlatan bir program bulunur. Başlatan programa veli, başlatılan programa çocuk denir. veli öldüğünde ya çocuk da ölür, ya daçocuk yetim kalmasın diye initvasi olarak görevi üstlenir. Bir işlem kendi altında bir başka işlem başlatırsa o işlemin velisi olur ve onun işletim sistemi altındaki kontrolunu elinde bulundurur. Veli-çocuk ilişkisi işletim sisteminin olanakları (sınırları) içinde derinleşebilir. İşletim sistemi bir kullanıcının iç içe başlatabileceği işlem sayısını ve sistemde çalışan toplam işlem sayısını sınırlayabilir.
İŞLEMLER ve STANDARD KÜTÜKLER
Bir kabuk altında çalışan her program UNIX açısından bir işlemdir. UNIX her işlemi ayrı ve tekil bir işlem numarası ile bellekte tutar. Bir komut çalışırken stdinsdtout ve stderr kütüklerini açmak gerekmez. Çünkü bu kütükler veli program tarafından çocuk işlemin kullanımına sunulmuş hazır açık kütüklerdir. Bu kütükler sıra ile 0, 1 ve 2 nolu kütükler olarak anılır ve programlarda bu kütük numaraları ile kullanılır. Bir işlem stdinolarak kullanıcının tuş takımını, stdout ve stderr olarak kullanıcı ekranını bilir.
Bu kütüklerin nereden alınacağı, nasıl yönlendirileceği komut yazılırken belirtilebilir. UNIX ortamındaki giriş/çıkış kütüklerini yönlendirme özelliği, programı değiştirmeden değişik bilgi saklama ortamlarından bilgi okuyabilme veya değişik ortamlara bilgi yazabilme olanağı getirir.
GİRİŞ/ÇIKIŞ KÜTÜKLERİNİ YÖNLENDİRME
Giriş kütüğünü yönlerdirmek için program komutundan sonra '<' simgesi kullanılır. Örneğin :
$ komut < okuma.dat
Bu örnekte standart giriş kütüğü yerine bilgiler okuma.dat kütüğünden satır satır okunarak programa aktarılır.
Çıkış kütüğünü ekrandan bir başka yöne yönlendirmek için :
$ komut > yazma.dat
komutu örneği kullanılır. Burada '>' simgesi çıkış bilgisinin yazma.dat kütüğüne yazılmasını sağlar. Daha önce var olan bir kütüğün sonuna ek yapmak için '>>' simgeleri kullanılır.
Çıkış bilgisinin hiç bir kütüğe yazılmadan silinmesi istenirse
$ komut > /dev/null
örneğinde olduğu gibi çıkış bilgisi olmayan kütüğe yönlendirilebilir.
stderr kütüğünü yönlerdirme işlemi normal koşullara göre biraz daha karmaşıktır. Burada kullanılan örnek :
$ komut 2>&1 > okuma.dat
biçiminde olunca 2 nolu kütük (stderr) önce 1 nolu kütüğe (stdout) yönlendirilmekte, sonra bir numaralı kütükokuma.dat kütüğüne yönlendirilmektedir. Burada "2>&1" simgeleri arasında boşluk bırakılmamalıdır.
KOMUT GİRME ve ÇALIŞTIRMA
Kullanıcı, kabuk program çalıştığında, ekranda komut girme simgesi ile karşılaşır. Buraya çalıştırılacak programın adını girer. UNIX kullanıcı için tanımlanmış PATH çevre değişkenindeki kütük yolu tanımlarını sıra ile arar ve yazılan programı ilk bulduğu yerden belleğe yükleyerek çalıştırır.
Çalışan program göreceli kütükleri kullanıcının yurdundaki kütük yolundan veya o anda bulunduğu alandan başlayarak okur veya yaratır.
İsterse kullanıcı bir programın kökten başlayarak tüm yolunu vererek başlatabilir. Bu durumda UNIX PATH değişkeni değerlerine bakmaksızın istenilen programı belirtilen kütük yolundan okuyup belleğe alır ve çalıştırır.
Komut satırında programa parametre aktarma olanağı vardır. Eğer bir program komut satırındaki parametreleri algılayabilecek biçimde yazılmış ise, komut satırına yazılan her parametre programın değişen seçeneklerle kullanılmasını sağlar. Komut satırında çift tırnak (") kullanılmadan yazılan her parametre arasındaki boşluklar kabuk program tarafından bilgi alanı ayıracı olarak kullanılır. Ama (") içine yazılan parametreler bir arada (boşluklar dahil edilerek) programa gönderilir. Örneğin :
$ komut param_1 param_2 param_3 ... param_n
çalıştırılan programa :
char *argv[] = {
      "komut",
      "param_1",
      "param_2",
      "param_3",
        ...
      "param_n"
      };
tanımındaki gibi aktarılır. Bu tablodaki toplam eleman sayısı (n+1) dir. Programa aktarılan ilk parametre komut satırında kaç parametre olduğunu belirtir. Tablodaki 0 numaralı eleman her zaman programın adını içerir.
$ komut param_1 "param_2 param_3 ... param_n"
biçiminde çalıştırılan programda, programa aktarılan parametre tablosu
char *argv[] = {
      "komut",
      "param_1",
      "param_2 param_3 ... param_n"
      };
tanımında olduğu gibidir. Bu örnekte toplam parametre sayısı (3) dür.
İŞLEMLER ARASI İLETİŞİM
PIPE Bir işlemin çıkışını diğerinin girişine yönlendirme işlemine verilen genel addır. Bu işlem komut satırında (|) işareti ile yapılabilir. Örneğin :
$ komut_1 | komut_2
Burada komut_1 çalışırken çıktısı komut_2 için giriş bilgisi olur. PIPE işlemi aslında aynı komut satırında çıkış ve giriş kütüklerini yönlendirme işlemidir.
Bir program içinden bu tür yönlendirme yapmak için popen (pipe open) komutu kullanılır. Bu komutta kütük adı yerine çalıştırılacak program yazılır ve PIPE işleminin nasıl olacağı okuma/yazma seçeneğinde belirtilir. Eğer bu seçenekte "w" kullanılırsa popen komutu ile açılan kütük ilgili program için çıktı kütüğüdür. PIPE komutu ile çalıştırılan program ise giriş bilgisini kendisini çağıran programdan alır. Eğer bu alana "r" yazılırsa, Çağırılan programın çıktısı çağıran program tarafından popen komutu ile açılan kütük aracılığı ile okunmuş olur.
ADLANDIRILMIŞ PIPE (NAMED PIPE)
Bu komut UNIX ortamında kullanılan eski bir işlemler arası iletişim yöntemidir. Önce adlandırılmış PIPEmknod komutu ile yaratılır. Birbirleri ile iletişim kuracak programlardan biri bu adlandırılmış PIPE'ı giriş kütüğü diğeri ise çıkış kütüğü olarak açar. Giriş kütüğü olarak açan PIPE'dan bilgi okur. Çıkış kütüğü olarak açan ise PIPE'a bilgi yazar. Tek yönlü iletişim bir başka adlandırılmış PIPE aracılığı ile diğer yönde de kurulabilir. Diğer bir deyimle bir PIPE çıkış kütüğü olarak açılmış ise aynı programda diğer PIPE giriş kütüğü olarak açılır. Diğer program ise öncekinin çıkış kütüğü olarak açtığını giriş, giriş kütüğü olarak açtığını çıkış kütüğü olarak açarsa iki yönlü iletişim kurulmuş olur.
Adlandırılmış PIPE bir kez yaratıldıktan sonra hep sistemde kalır.
SOCKET (AF_UNIX PROTOKOLÜ)
AF_UNIX protokolü kullanarak açılan socket ler kavram olarak PIPE kullanımına benzer. Bir programsocket dinlerken diğeri socket aracılığı ile mesaj gönderir, sonra cevap bekler. Bu kullanım biçimindeki en önemli değişiklik bir socket'in her iki program tarafından hem mesaj okuma hem de mesaj yazma ortamı olarak kullanılabilir olmasıdır.
socket dinleyen program önce socket bilgisini yaratır. Diğer program, bu socket bilgisini kullanır. İşlem bittiğinde socket yaratan program (dinleyen) socket bilgisini siler. Eğer sistemde aynı adla bir socket varsa, program yeni socket yaratamaz. socket kullanılıyor diye mesaj verip işlemi bitirir.
İŞLEMLER ARASI İLETİŞİM (IPC)
UNIX System V kavramları ile işletim sistemine gelen bu özellik üç temel bilgiden oluşur :
·        İşlemler arası ortak bellek kullanma,
·        işlemler arası mesaj kuyrukları oluşturma,
·        işlemler arası semaphore kullanımı.
Kavram olarak; ortak bellek, mesaj kuyrukları ve semaphore sistemde işletim sistemi tarafından denetlenen bellek alanlarının adlarıdır. Bir işlem bu kavramlardan birini kullanmak istediğinde işletim sistemi ya ilgili kavram için bellekte yer açar ya da mevcut kavramın adresini, adını veya anahtar bilgisini kullanıcının kullanımına sunar. Bellekteki her kavramın bir adı veya anahtar bilgisi vardır. Bu kavramı kullanacak program, anahtar bilgi aracılığı ile kavrama erişir, okur, değerini değiştirir veya kuyruğa yeni bilgi ekler.
Bu bölümde her kavramın nasıl kullanıldığı, anlamı kısaca anlatılmıştır.
·        ORTAK BELLEK
shmgetshmatshmdt komutları ortak bellek işlemlerinde programlar tarafından kullanılır.
shmget Bu komut işletim sisteminin, ortak bellek kesidi ataması yapması için kullanılır. Program hangi anahtar bilgi için ne kadar uzunlukta bellek ataması yapılacağını belirtir. Bu anahtar bilgi için daha önce atanmış alan varsa adresi programa geri dönerken, işletim sistemi hiç bir bilgi bulamaz ise komutun özelliğine göre iki işlem yapar :

o       Eğer komutta IPC_CREAT tanımlanmış ise hemen bellek alanı açar ve adını (identifier) programa geri döndürür.
o       Eğer komutta IPC_CREAT yoksa, bir başka program alan açıncaya kadar ilk programı bekletir.
shmat Bu komut daha önce shmget komutundan alınan ortak bellek adının komutu kullanan programa atanması için gereklidir. Atama ilgili ortak belleğin programdaki veri kesimine bağlanması anlamına gelir.
shmdt Bu komut daha önce atanmış ortak belleğin bağlantısını kaldırmak için kullanılır.

Örnek :

    shmid = shmget((key_t) SUBESHM,
                   sizeof(struct GDATA),
                   0666 | IPC_CREAT);
    shr_ptr = (char *)shmat(shmid, NULL, 0);
    
Bu komutlarla program adres değişkeni olan shr_ptr işletim sistemi tarafından yaratılan ortak belleği hem okuma hem de yazma amaçlı kullanabilir.

·        MESAJ KUYRUĞU
msggetmsgsndmsgrcv komutları mesaj kuyruğu kavramları için programlarda kullanılır.
msgget Bu komut mesaj kuyruğu adını almak için kullanılır. Eğer daha önce bu mesaj tipi için bellekte kuyruk açılmamış ise işletim sistemi IPC_CREAT seçeneği ile mesaj kuyruğunu açar ve tanımını programa geri gönderir.
msgsnd Bu komut bir kez msgget ile alınmış olan mesaj adını kullanarak mesaj kuyruğuna bilgi göndermek için kullanılır. işlem seçeneğinde IPC_NOWAIT varsa, mesajın kuyruklanması yeterlidir. Program işlemlerine devam eder. Eğer IPC_NOWAIT yoksa mesaj kuyruktan okununcaya kadar beklenir.
msgrcv Mesaj kuyruğundan bilgi okuyacak program mesaj adını msgget komutu ile alır, daha sonra okuyacağı mesaj numarasını kuyruktan almak için msgrcv komutunu kullanılır. İlgili program mesaj kuyruğuna aynı mesaj numarası ile mesaj koymuş ise onu okur. Eğer IPC_NOWAIT tanımlanmışsa ve mesaj bulunamaz ise okuyan program işlemlerine devam eder. IPC_NOWAIT kullanılmamış ise kuyruğa mesaj yazılıncaya kadar bekler.
Örnek :
    struct MSGBUF {
        long mtype;
        char msg[MAXMSG];
        };
    struct MSGBUF msgbuf;
             .
             .
             .
    *********** mesaj gonderen program *********
    msgid = msgget((key_t)SUBEMSG, 0666 | IPC_CREAT);
    msgtype = no;
    msgsnd(msgid, &msgbuf, 
           sizeof(struct MSGBUF), 
           msgtype, 
           IPC_WAIT);
    *********** mesaj okuyan program ***********
    msgid = msgget((key_t)SUBEMSG, 0666 | IPC_CREAT);
    msgtype = no;
    msgrcv(msgid, &msgbuf, 
           sizeof(struct MSGBUF), 
           msgtype, 
           IPC_WAIT);
    
Bu örnekte mesaj okuyan program msgrcv komutunda bekler. Aynı şekilde mesaj gönderen program da msgsnd komutunda bekler. Her iki komut işlemini bitirdikten sonra programlar bir sonraki adıma geçer. Eğer IPC_WAIT yerine IPC_NOWAIT kullanılmış olsaydı yukarıdaki örnekte gönderme işlemi yapan program kuyruğa bilgiyi yazıp hemen bir sonraki işleme geçecek, diğer programın mesajı alıp almamasını beklemeyecekti. Aynı mantıkla okuma yapan program msgrcv komutunda beklemeyecek, eğer mesaj yoksa veya daha hazır değilse bir sonraki işlemden program akışına devam edecekti.

·        SEMAPHORE
semgetsemop komutları ilgili kavram için programlarda kullanılır.
semget Bu komut istenilen anahtar bilgi için işletim sistemi tarafından atanan semaphore kümesinin adını (identifier) döndürür. Eğer aynı anahtar bilgi ile sistemede tanımlı semaphore kümesi yoksa ve komut kullanımında IPC_CREAT belirtilmiş ise işletim sistemi semaphore kümesi yaratır ve yaratılansemaphore'un adını döndürür.
semop Bu komut semaphore kullanımında yapılacak işlemleri tanımlamak için kullanılır. struct sembuf yapısında belirtilen işlemlerin ne amaç için kullanıldığı bu yapı tanımındaki bilgilerin alacağı değerlerle ilişkilidir. Bu yapı tanımında bulunan :

    short sem_num;
    short sem_op;
    short sem_flg;
    
değişkenleri yapılacak işlemi tanımlamada önemli değerler alır. sem_flg içinde bulunan IPC_NOWAIT ve SEM_UNDO işlev tamamlanmadığında semaphore işlemini geri almak için kullanılır. sem_num ilk değeri 0 ile başlayan ve aynı küme içinde yer alan semaphore'ları tanımlar.sem_op değeri artı bir sayısal değer ise semval değişkenini arttırır. Eğer sem_flg içinde IPC_NOWAIT tanımlanmamış ise bu işlev aşağıdakilerden biri oluşuncaya kadar bekler :

1.     semval değeri 0 olunca,
2.     semaphore kümesi bellekten silinince,
3.     işlevi başlatan program bir sinyal alıp işlemi kesince.
sem_op eksi bir değer ise semval değişkeni eksiltilir. Bu işlem için programın semaphore kümesini değiştirebilme yetkisi olmalıdır.

SERİ UÇ PROGRAMLAMA TEKNİKLERİ


·        TERMİNALSİZ SERİ UÇLAR İÇİN PROGRAMLAR
Terminalsiz seri uçlar için yazılan programlar, UNIX ortamına program kontrolunda diğer çevre birimlerini bağlayabilme olanağı getirir. Yazılan program gün başında çok kullanıcılı ortama geçildikten sonra veya bir kullanıcı tarafından istenildiği zaman başlatılabilir. Bu yöntemle işletim sisteminin bir parçası olabilecek sürücü program olmadan, herhangi bir çevre birimini UNIX ortamına bağlamak mümkün olur.

o       UNIX ortamında Seri Uçların tanımlanma biçimi
UNIX ortamında, işletim sistemi seri uçları iki biçimde tanımlar : Birincisi fiziksel seri uçlar; İkincisi ise pseudo seri uçlardır. Fiziksel seri uçlar kullanılan donanıma ilişkin seri uç sürücü programlarına bağımlı çevre birimi tanımlarıdır ama çoğu kez /dev/ttynn biçiminde tanımlanır.Pseudo seri uçlar gerçekte olmayan ancak TCP/IP ve telnet servisi tarafından üretilen sahte seri uçlardır.
Seri uçlara ait çevre birimi tanımlarının sahibi çoğu zaman "root" adlı kullanıcıdır. gettyprogramı bir kullanıcı sisteme girdikten sonra bu seri ucun erişim haklarını yalnız ilgili kullanıcıya yönlendirir ve diğer kullanıcıların bu seri uca erişimini kaldırır.
Seri uca bağlı bir terminal yoksa getty programı kullanılmamalıdır. Bu işlem en güzel,/etc/inittab kütüğündeki ilgili terminal bilgilerinde getty tanımının respawn özelliğini offkonumuna almaktır. Böylece aynı seri uca ileride bir terminal bağlanması söz konusu olduğunda /etc/inittab bilgileri bozulmadan off konumu respawn yapılarak terminalden logingörüntülenmesi sağlanmış olur.
Seri uca terminal bağlanmayacak ve buraya bir başka çevre birimi bağlanacaksa, bu çevre biriminde olması gereken en önemli özellik, gönderilen mesajları algılayan bir programın ilgili çevre birimi üzerinde çalışır durumda olabilmesidir.
UNIX üzerindeki program, ilgili seri ucu kullanabilmek için bu kütüğü open komutu ile açmalıdır. Seri uç kütüğü UNIX için /dev/ttynn biçiminde tanımlanır. Program bu kütüğü açarken hem OKUMA hem de YAZMA işlemi yapacak biçimde koşullandırılır. UNIX ortamında bu kütük daha önce mknod komutu ile yaratılmış olduğundan, kütüğün açılırken yoksa yaratılması söz konusu değildir. Çünkü bu tür kütükleri "root" adlı kullanıcı yaratabilir. Eğer kullanıcının kütüğe erişme yetkisi yoksa kütük açma işlemi başarı ile bitmez.
Kütük açarken dikkat edilmesi gereken konular :

1.    Eğer seri uca bir modem bağlanmış ise, modemler telefon hattından karşı taraftaki modemi görmeden DTR ve CD sinyalini yakmazlar. Bu durumda program seri uca ait kütüğü açamayabilir. Bu gibi durumlar için open komutunda N_DELAY konumu kullanılmalı, modemle iletişim kurulup mesaj alış verişi tamamlandıktan sonra N_DELAY fcntl komutu ile kaldırılmalıdır.

2.    Seri bağlantıda sistemde tanımlı RS-232 uçlardan TX,RX,CTS,DTR ve Toprak bağlantıları mutlaka bulunmalıdır. Eğer sistemde seri uç çoklayıcı donanım kullanılıyorsa ve bu donanıma ilişkin sürücünün parametrik bilgileri varsa UNIX ortamına uyumlu olmaması olasılığına karşın seri uçların tümünde protokol tanımı "NO PROTOCOL" biçiminde hazırlanmalıdır. Bu özellikler yoksa fcntl komutu ile seri uc, protokolsüz çalışacak biçimde düzenlenmelidir.

3.    Seri uç donanımı UART kurallarına uygun ise seri uc iletişim hızı en çok 38400 olabilir. Bu hızın üzerinde iletişim kurmak söz konusu olduğunda, işletim sisteminin özel komutları varsa kullanılmalıdır. Unutulmaması gereken özellik seri uç iletişim hızı 9600, 19200 ve 38400 olabilir. Diğer ara hızlarda seri uç ile iletişim kurulamayabilir.

o       Seri uç parametrelerini düzenleme
UNIX ortamında seri uçların kullanım biçimi terminal kullanımına göre düzenlenmiştir. BuradaBreak tuşu, yazılamayan karakteri çevirme özelliği gibi bazı tanımlar önceden terminal sürücü programı tarafından düzenlenmiş filitreler oluşturulmuştur. Bu düzenleme seri uçtan bir bilgi okuma veya seri uca bir bilgi yazma adımlarında istenilmeyen sonuçlar verebilir. Özellikle çevre birimini kontrol etmeyi amaçlayan karakterler (STX, ETX, NULL gibi), filitrelerden geçmeyebilir. Seri uç programları ham veri işleme konumunda iken işletim sistemi ve sürücü programlar tarafından düzenlenmiş filitrelerin parametrelerini değiştirmelidir. Parametre değiştirme işlemi fcntl komutu ile yapılır.
fcntl komutu için kullanılacak parametrik bilgilerin alabileceği değerler :

c_lflag = 0;
c_iflag = IGNPAR | IXANY | IGNBRK;
c_oflag = 0;
 
for(a=0;a < NCCS;a++)
    c_cc[a] = 0;
 
c_cc[4] = 1; /* karakter sayısı            */
c_cc[5] = 1; /* zaman asımı bekleme süresi */
 
c_cflag = CLOCAL | CS8 | CREAD | baud_rate;
olarak tanımlanabilir.

o       Ham bilgi okuma ve yazma kuralları
UNIX ortamında bir kütükten ham bilgi okuma read komutu, bir kütüğe ham bilgi yazmawrite komutu ile olur. Seri uçlara ham bilgi (donanım karakter tabanlı olduğu için), bir byte gönderme veya bir byte okuma biçimindedir. Tamponlanmış giriş/çıkış işlemi yapılmamalıdır. Hız açısından (özellikle bilgi gönderirken) tamponlanmış bilgi alış verişi yapılacaksa, tampon alan kontrol edilmeli, tampon alan dolduğunda gönderme durdurulmalı, boşalınca tekrar başlatılmalıdır. Terminal kullanımına ait olan XON/XOFF protokolü ham veri işleme konumunda kesinlikle kullanılmamalıdır. Çünkü bu bilgi (XON veya XOFF), gerçekte karşı taraftaki çevre birimine gitmesi gereken bir bilgi olabilir.
Bilgi okurken en çok bir byte bilgi tamponlanmalı, mümkünse tampon alan boyu 0 olmalıdır.
Bilgi okuma işleminde doğrudan read komutu kullanılacak olursa program, okuma işlemi yapılmadan bu komuttan çıkmaz. Ama çevre birimine bilgi gönderen ve çevre biriminden okuma yapan bu tür progamlara sistem içindeki bir başka işlemden bilgi akışı olabilir. Bu durumda çevre biriminden okunacak bilgi yoksa program bir başka işleve geçebilmeli, kendisine gelen bir başka bilgi veya mesaj olup olmadığını anlayabilmelidir.
UNIX ortamında kesinti (Interrupt) olanağı olmadığından, bu bilgi doğrudan işletim sistemi kontrolu altında olduğundan seri uç okuma programında read komutu yerine select komutu kullanılmalıdır. Bu komut ile açılmış kütüklere ait kütük numaralarından bir küme oluşturulur. Oluşturulan kümeden bilgi gelmesi beklenir. Eğer kümenin hiçbir elemanından bilgi gelmiyorsa belirtilen zaman aşımında işlev, hata kodu ile programa döner. Eğer bir bilgi gelmiş ise, kümedeki kütüğün numarası programa döner. Bu durumda program, ilgili kütükten gelen bilgiyi okur.

o       Örnek program tanımı
Örnek olarak seri uçtan gelecek bilgi protokol gereği

biçiminde olsun. Program bu mesajı alınca önce LRC denetimi yapacak daha sonra mesaj doğru alındı ise ACK gönderecektir. Hata varsa NACK gönderecektir.

o       Örnek program kodu

#define NACK 0x15
#define ACK  0x06
#define ETX  0x03
#define UPD_NFDS(x) if(nfds<(x))nfds=(x)
 
main()
{
fd_set fdx;
struct timeval tv;
struct termios term;
int nfds = 0;
char c;
int  s, fd, sec, msec;
 
fd = open("/dev/tty00",2);
 
/* seri uc tanimlarini duzenleme */
tcgetattr(fp_prt,&term);
term.c_lflag = 0;
term.c_iflag = IGNPAR | IXANY | IGNBRK;
term.c_oflag = 0;
for(a=0;a < NCCS;a++)
    term.c_cc[a] = 0;
/* karakter sayısı */
term.c_cc[4] = 1; 
/* zaman asımı bekleme süresi */
term.c_cc[5] = 1; 
term.c_cflag = CLOCAL|CS8|CREAD|B9600;
tcsetattr(fp_prt,TCSANOW,&term);
 
sec = 0; msec = 100;
tv.tv_sec  = sec;
tv.tv_usec = msec;
FD_ZERO(&fdx);
FD_SET(fd,&fdx);
UPD_NFDS(fd);
 
while(1) {
    lrc = 0;
    s = select(nfds+1, &fdx, NULL, NULL, &tv);
    if(s >= 0) {
        /* STX okunur */
        read(s,&c,1);    
        /* mesajin kalani ETX dahil
        okunur ve LRC hesaplanir */
        while(c != ETX) {
           read(s,&c,1);
           lrc = lrc ^ c;
           }
        /* LRC okumak icin */
        read(s,&c,1);
        /* LRC hatasi varsa NACK gonder */
        c = (c != lrc) ? NACK : ACK;
        write(s,&c,1);
        }
    }
}
Bu örnek programda, kodlamayı kısaltmak için hattan gelen mesajın protokoldaki yapıda sonuna kadar hatasız geleceği varsayılmıştır.

·        TERMİNALLER İÇİN TÜM EKRAN (FULL SCREEN)
PROGRAM YAZMA TEKNİKLERİ
Bu bölümde yer alan anlatım için kullandığınız UNIX program geliştirme ortamındaki curses kitaplığı yayınlarına bakmak, varsa diğer özel işlevleri de kullanmak gerekebilir.

o       Karakter tabanlı ekranlarda tüm ekran kullanımı (curses)
UNIX ortamında karakter ekranlar satır satır kayan komundadır. Tüm ekranı (24 x 80) karakter biçiminde kullanmak. Yazılan her harfi anında algılayabilmek ancak ham bilgi alma ve yazma konumunda geçerlidir.
Ham bilgiyi ekrandan alma ve ekrana yazma işlemi UNIX program geliştirme ortamındacurses kitaplığı ile mümkündür.
curses gerçek anlamda bir ekranı ham veri işleme konumunda kullanan kitaplıktır. Bu kitaplıkta yer alan işlevlerle uygulama programları ekrandan bir karakter okur, ekrana bir karakter yazabilir. Halbuki komut konumunda yazılan bilgi UNIX tarafından Enter tuşuna basılmadan işleme alınmaz. Komut konumundaki bu mantığa tampon alandan okuma tekniği denir. Ham veri işleme konumunda ise program yazılan her tuşu anında algılar, tuşun gereği olan işlemi anında gerçekleştirir.
curses önce ekranı ham veri işleme konumuna alır. Daha sonra tüm ekranın iki kopya olarak bilgilerini saklar. Birinci kopya görüntülenen ekran, diğeri ise program tarafından günlenen ekran alanıdır. Her refresh komutu çalıştığında, curses iki kopya arasındaki farklı karakterleri belirler ve yalnız bu karakterleri ekrana gönderir. Bu nedenle curses ekran üzerindeki bir karakterin nereye yazılabileceğini bilmelidir. Her ekranın karakter görüntüleme komutları üretici firmalara göre değiştiğinden, ekran özellikleri termlib veya termcap veri tabanındaki tanımlardan alınır. curses kitaplığının doğru çalışması için kullanılan terminalin özellikleri termlib kitaplığına tanıtılmalıdır. Bu işlem için tic komutu kullanılır. curses UNIX kullanıcısının çevre değişkenlerinden TERM bilgisini kullanarak hangi terminal ile çalıştığını saptar ve ekrana bilgiyi bu terminalin özelliklerine göre gönderir.

o       Ekran tanımlama
Bir ekranı ham veri işleme konumuna almak için curses kitaplığındaki initscrcbreak,noechononl işlevleri sıra ile kullanılır. Bu işlemler ekranı ham veri işleme konumuna alır.
Ekranı tekrar komut işleme konumuna almak için echo ve endwin işlevlerini çalıştırmak gerekir.
Ekran ham veri işleme konumuna alındığında curses kitaplığı bu ekran için bir gösterge tanımlar. Bu göstergenin adı stdscr olarak belirlenmiştir. Terminal, ham veri işleme konumuna alındığında tuş takımından girilen bilgi iki biçimde algılanabilir. Ya program tuş takımı bilgilerini de ham olarak okur uygulama içinde karakterlerin ne anlama geldiğini belirler, ya da curseskitaplığı basılan bir tuşun termlib kitaplığındaki karşılığını bulup ilgili tuş değerini çevirilmiş olarak programa döndürür. Bu işlem için keypad işlevi çalıştırılır.
Yukarıda tanımlanan işlevlerle ekran ham veri işleme konumuna alındığında movegetch,addch işlevleri kullanılarak bilgi, ekranın istenilen yerine yazdırılır veya tuş takımından okunur.
Bir ekrana istenilen bilginin çıkması için refresh işlevinin çalıştırılması gerekir.

o       Pencere tanımlama
stdscr altında bir veya daha çok pencere açmak, pencerelere hareket ettirmek curseskitaplığı kullanımı ile mümkündür. Pencere açma işlevi newwin ile yapılır. Burada pencerenin ekrandaki (stdscr) başlangıç noktası ve boyutları belirtilir. Açılan pencere werease, delwingibi işlevlerle kapatılır.
Bir pencere kapatılınca ekrandan silinmesi için daha önce açılmış pencereler touch işlevi ile yenilenmeli, böylece kapanan pencerenin bıraktığı boşluk değir pencereler ile doldurulmalıdır.

o       Pencereden bilgi okuma, pencereye bilgi yazma
Pencereye bilgi yazarken pencerenin içindeki imleç adreslemesi pencerenin sol üst kösesine göre (0,0) kabul edilerek hesaplanır. Böylece pencerenin hareket ettirilmesi, yerinin değişmesi programlarda yeniden hesaplama yapmayı gerektirmez.
Bir pencereden bilgi okurken wgetch işlevi kullanılır. Aynı pencereye bilgi yazmak içinwaddch işlevi kullanmak gerekir. move işlevi yerine imleç hareketi için wmove işlevi kullanılır.

  



ÖZDEVİNLİ (RECURSIVE) PROGRAMLAR

BİRAZ TARİHÇE
Bilgisayarların ilk yapıldığı yıllarda, program kodu ve veri aynı alanda saklanırdı. O zamanlar çok kullanıcı ortam yerine tek kullanıcılı ortamda çalışma olduğundan bu tür kodlama sorun çıkartmıyordu. İşletim Sistemleri gelişip çok kullanıcılı ortama geçiş başlayınca bellekte aynı programdan birkaç kopya bulunması zamanında en pahalı donanım olan belleğin lüzumsuz harcanmasına neden oluyordu. Bilimsel açıdan bakıldığında derleyicilerin ürettiği kod üç ana bölümden oluşuyordu. Program komutları, değişmez değerler ve kullanıcıya göre değişen bilgiler. Donanım bu yapıya göre gelişirken, yani bellek kesimlere bölünürken işletim sistemleri de programları belleğe yüklerken bu ayrımı göze aldı. Bir programın değişmeyen bölümlerinden yalnız bir kopya saklandı. Yalnızca değişen bölümler için aynı programı kullanan değişik kullanıcılara ayrı bellek kesimleri açıldı. Bu yapı derleyicilerde tekrar girilebilen (reentrant) program kodu üretilmesini zorunlu kıldı. Tekrar girilebilen program kodunda her kullanıcı için son yapılan işlem, program durum bilgisi (program status word) adlı bir alanda saklandı. Aynı kod paylaşımlı olarak birden çok kullanıcı tarafından kullanılabilir oldu. Her kullanıcı kendi verileri için açılan kesimde bilgilerini sakladı. İşletim Sistemlerinin bu olanağı kullanıcıların özdevinli (recursive) program yazmalarına olanak verdi.

ÖZDEVİNLİ PROGRAM

Özdevinli programlarda bir işlev çalışırken bitmeden kendisini çağırır. Çağırılan işlevin sonucu, çağıran işlevde kullanılır. Görünüşte karmaşık olan bu olay, aslında donanımın, işlemcinin "stack" bilgilerinin program içinde verimli bir biçimde kullanılmasını sağlar. Örneklemek gerekirse, Matematikte :

    f(n) = f(n-1) + f(n-2)
biçiminde yazılan Fibonacci seri açılımı bu tür programların anlatımı için en kolay örnektir. Burada f(n) değerini hesaplamak için önce f(n-2) ve sonra f(n-1) değerlerini bilmek gerekir. Yazilan bir programda f işlevi aşağıdaki gibi kodlanırsa :

    f(int n)
    {
    return (f(n-1) + f(n-2));
    }
Bu işlev kendisini bir kez n-1 için bir kez de n-2 için çağırır. Aynı işlev n-1 değeri için kendisini bir kez n-2 ve bir kez de n-3 için çağırır. Burada her çağırma işleminde n değeri bir azalmaktadır. Sonunda n=0 ve n=1 değerlerine gelindiğinde işlev değişmez bir değer döndürmeli kendi çağırmayı durdurmalıdır. Yani

    f(int n)
    {
    if(n == 0 || n == 1) return 1;
    return (f(n-1) + f(n-2));
    }
Biçiminde kodlama değiştirilirse, işlev n=0 ve n=1 için kendini çağırmayı durdurur. Örneklemek açısından n=4 için işlevin durumunu göstermeye çalışalım :

              f(4)
               (5)
       f(3)    +     f(2)
        (3)           (2)
    f(2) + f(1)   f(1) + f(0)
     (2)     1      1      1
 f(1)+f(0)
   1    1

ÖZDEVİNLİ PROGRAMLARDA DEĞİŞKENLER

Bu tür programlarda değişkenler otomatik değişken olmalıdır. İşlev dışında tanımlanan değişkenleri kullanmak istemeyen sonuçlar alınmasına neden olabilir. Özellikle işleve parametre olarak geçirilen değer, işlev dışında "global" tanımlanmamalı, "stack" üzerinde bulunan otomatik değişkenler olmalıdır. Bilindiği gibi otomatik değişkenler işlev bitince bellekten silinmektedir. Özdevinli işlevlerde, çağırılan işlevin sonucu bir önceki işleve geri dönecek biçimde bir otomatik değişkene atanmalı veya atama işlemini gerçekleştiren bir deyimde kullanılmalıdır.

UYGULAMADA ÖZDEVİNLİ İŞLEV KULLANIMI

Bir seriden her seferinde bir byte okuyup işleme almak bu tür programlar için güzel bir örnektir. Örneğin hattan gelen mesaj analizinde bu tür işlev kolaylıkla kullanılır. Özellikle mesaj boyu bilinmiyor ancak mesajın nasıl biteceği biliniyorsa özdevinli işlev kullanmak programın akışını kolaylaştırması açısından önemlidir.
Aşağıdaki örnek program okunan mesajın sonunda "newline" karakterini bulunca sonucu yazdırır.

#include 
main()
{
char buf[300];
mesaj_oku(buf);
puts(buf);
}
 
mesaj_oku(char *p)
{
char c;
if((c = getchar()) != '\n') {
    *p = c;
    mesaj_oku(++p);
    }
else *p = '\0';
return;
}


LINUX VE KABUK PROGRAMLAMA (SHELL PROGRAMING)
Bir programi kod safhasindan çalisabilir bir hale getirebilmek için ilk önce derlememiz gerekir. Derleyiciler o kodu üzerinde çalistigimiz isletim sistemine uyarlarlar. Fakat pazi program kodlari derleme islemi gerektirmez. Bunlar direk isletim sistemi tarafindan yorumlanabilen "Script" tabir ettigimiz kod parçaciklaridir. Bu bir HTML sayfasindaki JavaScript olabilir veya Linux üzerinde bir kabuk programi olabilir. Kabuk programlariyla isletim sistemi üzerinde zahmetli olacak bir çok islem kolayca yapilabilir. Kabuk programlarinin aslinda diger programlama dillerinden pek farki yoktur. Genelde diger dillerle ayni mantigi kullanir. Simdi bu kabuk programlarinin nasil yazildigina bakalim.

Kabuk programlari da diger diller gibi degiskenler, döngüler, kosullu ifadeler vb. kullanabiliriz. Programi yazmaya baslarken ilk satirda ozel bir ifade kullaniriz. Bu isletim sisteminin hangi kabugunu kullanacagimizi belirtir.

NOT: Kabuk isletim sistemi ve kullanici arasinda tercümanlik yapan bir kilavuzdur diyebiliriz. Kullanicinin komutlarini yorumlayarak isletim sistemine iletir.

NOT2:Kaydettiginiz programi çalistirmak için dosya modunu 700 yapmaniz gerekir. Bunu yapmaniz için...:
Linux:tEmEl~$ chmod 700 dosya_adi (veya ayni seyi diger bir yolla da yapabiliriz)
Linux:tEmEl~$ chmod +x dosya_adi --> +x execute anlamina geliyor.
Linux:tEmEl~$ dosya_adi --> bu da yazdiginiz programi çalistirmak için.

DEGISKEN KULLANMA

Linux'te degiskenlerin belirli bir tipi yoktur. Degiskenleri tanimlarken string, integer, float vb. olduklarini belirtmenize gerek yoktur. Isletim sistemi bunu sizin yerinize yapar.

Mesela :

---------degisken.sh---------
#!/bin/bash
deger ="Temel KARABACAK"
sayi = 10
---------degisken.sh---------


Simdi bu programin neler yaptiguna bir bakalim. Ilk satirdaki ifade bu programin çalistigi sürece "/bin/bash" kabugunu kullanmasini belirtiyor. Ikinci satirdaki ifade ise deger degiskenine "Temel KARABACAK" degerini atiyor. Üçüncü satirda ise sayi degiskenine 10 degeri ataniyor.


EKRANA YAZDIRMA
Bir önceki yazdigimiz program hiç bir islem yapmiyordu. Simdi bir takim islemler yapan bir program yazalim. Mesela ekrana bir seyler yazdirsin.


-------yazdir.sh-------------
#!/bin/bash
echo "Temel KARABACAK"
-------yazdir.sh-------------


veya bunu farkli bir sekilde yapalim :

-------yazdir1.sh-------------
#!/bin/bash
temel="Temel KARABACAK"
echo "$temel Kondor'un bir uyesidir."
-------yazdir1.sh-------------

Yukardaki programin neler yaptigina bir gözatalim. Ilk iki satirin ne yaptigini daha önce ögrenmistik. Son satirda ise yeni bir komut var. "echo" komutu ekrana yazdirmak için kullanilan bir komuttur. Echo komutu ile ekrana bir degiskenin degerini yazdirmak istersek $temel diyerek bu sözcügün bas tarafina "$" isareti koyarak bir degisken oldugunu belirtiriz.

PROGRAM IÇINE AÇIKLAMA SATIRLARI KOYMAK

Linux'te açiklama satirlari koymak için # karakterinden yararlaniriz. Bu karakterin anlami bu satiri iptal et ve okumadan direk diger satira geç demektir. Yanliz ilk basta programa baslarken yazdigimiz "#!/bin/bash" ifadesi bir istisnadir.
Örnegin...:

--------------aciklama.sh---------------
#!/bin/bash
#Bu satir sistem tarafindan hiç okunmayacak.
#Asagidaki islem ismimi ekrana yazdiracak.
echo "Temel"
--------------aciklama.sh---------------

KOSULLU IFADELER(IF STATEMENTS)

Diger programlama dillerinde oldugu gibi kabuk programcilarinda da karsilastirmalar yapabiliriz. Bu diger dillerdekine çok benzer. Simdi bununla ilgili küçük bir uygulama yapalim.

---------if.sh------------
#!/bin/bash
deger1=1
deger2=100
#Eger deger1 ve deger2 esitse birinci islem gerçeklesir.
if [ $deger1 -eq $deger2]
then
echo "Bu iki deger ayni"
else
echo "Bu iki deger farkli"
fi
---------if.sh------------

Ilk üç satida yazanlari daha önceden biliyoruz. Dördüncü satirda ise if komutu basliyor. Linux'ta if komutu "if" ile baslar ve "fi" ile biter. If komutundan sonraki ifadeleri [] parantezler içine almalisiniz. Bu parantezlerin içindeki ifadeler mutlaka parantez kenarindan bir bosluk tusu kadar uzakta olmalidir. Yoksa yazdigimiz program çalismayabilir. Then ifadesi ise "if" ifadesinden sonraki kosulun gerçeklestigi zaman çalistirilacak komut veya komutlari belirtir. Else ifadesi ise if ifadesinden sonraki kosulun gerçeklesmemesi sonucu çalistirilacak komut veya komutlarin girildigi bölümdür. Simdi yukaridaki programda iki farkli degiskenin karsilastirilmasi var. deger1 ve deger2 degiskenleri karsilastiriliyor. Karsilastirma komutu için "=" ifadesi yerine ise "-eq" kullanilmis. Bu ifade iki degiskenin "equal" olup olmadigini kontrol ediyor. Linux'ta sayisal karsilastirmalar "-eq" gibi ifadelerle stirngsel yani kelime karsilastirmalari ise "=, !=" gibi ifadelerle yapilir. Diger kontrol degiskenlerini bölüm sonunda yazacagim. Eger ikisi de ayniysa ekrana "Bu iki sahis ayni kisi." Mesaji yazilacak. Fakat bizim programimizda bu iki degisken de birbirinden farkli. Programda iki degiskenin farkli olmasi durumunda ise ekrana "Bu iki sahis farkli kisi." Mesaji yazdirilacakti. Bu yüzden programimizin çiktisi else ifadesinden sonraki bölüm olacak. Simdi farkli bir deneme yapalim.

--------if2.sh----------
#!/bin/bash
#Buradaki $# parametre sayisi anlamina geliyor.
if test $# -eq 0
then
echo "Hiç parametre girmediniz."
else
#Birinci parametreyi ekrana yaz. Ikinci parametre olsa $2 olurdu.
echo $1
fi
--------if2.sh----------

Karsilastirma ifadeleri :

-eq --> equal yani esit mi?
-ne --> not equal yani esit degil
-ge --> greater equal yani büyük esit
-le --> little equal yani küçük esit
-lt --> little yani küçük
-gt --> greater yani büyük
= --> string olarak esit
!= --> string olarak esit degil

WHILE DÖNGÜSÜ

Linux'te çesitli amaçlarla kullanilan döngüler yer alir. Diger dillerde oldugu gibi farkli bir döngüyle yaptigimiz isi bir baskasi ile de yapabiliriz. Fakat Linux'ta for döngüsünde biraz farklilik vardir ve eger sistem yöneticisi isek bu bizim çok isimize yarar. Simdi küçük bir örnekle while döngüsünü açiklayalim.

-------while.sh----------
#!/bin/bash
sayici=1
sayi=22
#while döngüsü basliyor
while [ $sayici -lt $sayi ]
do
#Sayimizin degerini ekrana yazdiriyoruz.
echo "Sayimizin degeri : $sayici"
#sayici degiskeninin degerine 1 ekliyoruz.
#bunu yapmazsak program sonsuz döngüye girer.
sayici=`expr $sayi +1`
done
echo "Sayma islemi bitti."
-------while.sh----------

Yukaridaki örnegi biraz açiklayalim. While satirinda sayici ve sayi degiskenlerinin degerleri karsilastiriliyor. Eger kosul dogruysa sayici degiskeninin degeri ekrana yazdiriliyor. Açiklamalardan sonraki satirda ise sayici degiskeninin degeri 1 artiriliyor. Buradaki "expr" ifadesi matematiksel bir islem yapilacagini belirtiyor. Müteakip satirda ise "done" ifadesi var. Linux'ta while döngüsü "do" ile devam eder ve "done" ile biter. "do" ifadesinden sonra yapilacak islemleri gireriz. While komutunun sona erdigini ise "done" ifadesi ile belirtiriz.

UNTIL DÖNGÜSÜ
Until komutu while döngüsünde oldugu gibi bir takim isleri tekrar etmemizi saglar. Simdi bu komutun yapisina bir göz atalim.

----------------repeat.sh----------------
#!/bin/bash
deger1=0
deger2=10
#until komutu basliyor.
until [ $deger1 -nq $deger2 ]
do
#yapilacak isleri buradan itibaren yazacagiz
echo "$deger1 degeri : --> $deger1"
deger1=`expr $deger1 +1`
done
#hepsi bu kadar iste!
----------------repeat.sh----------------

FOR DÖNGÜSÜ





 
For döngüsü diger döngülerden mantik itibariyle farklidir. Bunu bir örnek üzerinde açiklayalim.

----------for.sh---------------
#!/bin/bash
#for döngüsü için önceden degisken tanitmamiza gerek yok.
#degiskenimizi döngü içinde tanimliyoruz.
for deger in 1 2 3 4 5 6 7 8 9 0
do
echo "deger degiskenimizin degeri --> $deger"
done
----------for.sh---------------

yukarida klasik bir for döngüsü yazdik. Bu döngünün basinda deger degiskeninin her döngü için alabilecegi degiskenleri tanimladik. Buna göre deger degiskeni 1 2 3 4 5 6 7 8 9 0 degerlerini alabilirdi. Ve do-done arasinda da ise yapilacak islemleri tanimladik. Burada deger degiskeninin degeri her seferinde ekrana yaziliyor. Buraya kadar da görüldügü gibi döngü mantigi döngü_ismi-do-done seklinde.

EXPR KOMUTU ILE YAPILACAK ISLEMLER

Expr komutu ile matemetiksel islemler yapilabilecegi gibi stringsel islemler de yapilabilir. Simdi bunlari teker teker inceleyelim:

Matemetiksel Islemler:

* --> Çarpma
/ --> Bölme
% --> Mod alma
= --> Esit
> --> Büyük
< --> Küçük
<= --> Küçük esit
>= --> Büyük esit


Stringsel islemler :

1) expr string1:string2
iki stringi karsilastiriyor.

2) expr length string
string'in uzunlugunu buluyor.

3) a=batman
expr substr $a 1 3
1 nci kelimeden sonra 3 karakter kopyaliyor. Deger burada "bat" olur.
Expr substr $a 4 3
Buradaki deger ise "man" olurdu.

4) expr index $a m
a degiskeni içinde "m" karakterinin yerini söylüyor. Dolayisiyla deger 4 olur.




Simdilik bu kadar. Devami gelecek

TCP/IP İLE PROGRAMLAMA





 

TCP/IP iletişimi hakkında kısa bir açıklamayı iletişim bölümünde daha önce anlatmıştım. Ayrıca dileyenler, INTERNET bağlantıları ve bilgisayarlar arasındaki mesaj trafiği hakkında bilgi edinmek için INTERNET ağlarıkonulu dökümanı da inceleyebilirler.
Burada TCP/IP iletişimi için C programlarında nasıl bir yöntem izlendiğine ve programlarda kullanılan komutların özelliklerine değineceğiz. Sonra örnek programlarla bu bilgileri nasıl kullandığımızı göstereceğiz.
KISA ÖN BİLGİ
TCP/IP genelde bir bilgisayar ortamında iki program arasında iletişim kurulması için kullanılan bir protokoldur. Burada programlar İşgören (sunucu) ve İşveren olarak iki ayrı konumda çalışır. Kısaca söylemek gerekirse programlardan biri gelen bilgiyi işleyip diğer programa göndermeyi gerçekleştirirken, bilgiyi alan program, işlenmiş bilgiyi görüntüleri ya da kullanır. Bu kavram bize iki değişik ortamda çalışan programlar yazma olanağı getirir.
Genelde kullanıcıların hepsinde yalnız kullanıcı arayüzü olan programlar çalışırken, merkezde veri tabanı erişimi, yazici paylaşımı ve dış dünya ile bağlantı için gereken programlar bulunur. Kullanıcı bilgilerinin ekrandan alınması sırasında kullanıcı bilgisayarında çalışan program merkezdeki programla bağlantı olmadığından tüm işlem yükü yalnız kullanıcı bilgisayarında kalır. Bu işlemler için merkez bilgisayar bir emek harcamaz. Bilgi tamamlanıp merkeze gönderildiğinde ilgili program, gelen bilgi üzerinde gereken işlemleri yapıp sonuçları kullanıcının bilgisayarına iletir. Aradaki iletişim sürekli değildir. İletişim yalnız mesaj alış verişi sırasında kurulur. Ancak aynı anda birden çok kullanıcı bir merkeze bağlantı kurabildiğinden merkezdeki bilgisayar yüksek işlem gücü ile donatılır. Kullanıcı bilgisayarları ise herkesin kullandığı PC'ler olabilir.
Bazı koşullarda tüm kullanıcılara her işi yapan yetki verilmez. Ancak kullandıkları programın veri tabanına ekler yapması, ya da verilerin bazılarını değiştirmesi gerekebilir. Bu durumda İşgören (Sunucu) tüm yetkilerle ile donatılır ve işveren program gerekli mesajı göndererek işlemin yapılmasını ister. Burada işgören ve işveren programlar aynı bilgisayarda çalışabilir. Örneğin bir java applet ile ekrandan girilen bilginin diske yazılması hakkı bir işgören programa mesaj gönderilerek yapılabilir. Burada java applet, bilgiyi alırken kullanıcının yetkisi olup olmadığını, güvenlik kuralları çerçevesinde kontrol eder (kullanıcı adı ve şifresi almak gibi) ve uygun güvenlik bilgilerini mesajla birlikte işgörene gönderir.
Bu nedenle TCP/IP iletişim programları kullanıcılara işveren ve işgören programlar yazarak uygulama alanlarını genişletme olanağı getirir.
Anlattığım ya da anlatacağım bazı temel kavramlar, TCP/IP hakkında teknik bilgileri içermektedir. Amaç, çeşitli uygulamalarda bu kavramları kullanarak iletişim programları yazılımını kolaylaştırmaktır.
Tanımlanmış IP protokolları
Bu tabloda yer alan IP protokollarının kullanım biçimleri TCP/IP iletişimi için önemlidir. Örneğin, programlarda kullanılan socket açma komutunun son parametresi aşağıdaki IP protokollarından biri olmalıdır.
IP Protokolları
Değeri
Açıklama
IPPROTO_IP
0
TCP için standart protokol
IPPROTO_ICMP
1
Internet Kontrol Mesajları Protokolu
IPPROTO_IGMP
2
Internet Grup Yönetim Protokolu
IPPROTO_IPIP
4
IPIP tünelleri
IPPROTO_TCP
6
(TCP) Transmission Control Protocol
IPPROTO_EGP
8
Başka bir bilgisayardaki eşik protokolu
IPPROTO_PUP
12
PUP protokolu
IPPROTO_UDP
17
Kullanıcının tanımladığı Datagram Prtokolu
IPPROTO_IDP
22
XNS IDP Protokolu
IPPROTO_RAW
255
Ham IP paketleri
TCP socket protokolları
TCP socket'lerinde bağlantılı türleri socketin özelliğine göre değişir. TCP iletişiminde iki ana kavram vardır. Biri bağlantılı, diğeri bağlantısız iletişim. Bağlantılı iletişimde socket'ten mesaj bekleyen (listen komutu ile socketi dinleyen) programa bağlantı, connect komutu ile yapılır. Bağlantı sağlandıktan sonra mesaj gönderme ve alma işlemi read ve write komutları ile gerçekleşir. Bağlantılı iletişimde kullanılan socket türü SOCK_STREAM olmalıdır. TCP/IP üzerinden iletişimde, hattın yoğunluğu ve kalitesine bağımlı olarak parçalanan TCP paketleri bu socket türü kullanıldığında alıcı socket altında sıralanır ve birleşirilerek TCP katmanına ulaştırılır. Bu durumda uygulama programı, bir read komutu ile tüm mesajı bir seferde okuyabilir.
Kısa mesajlar SOCK_DGRAM socket üzerinden iletilebilir. Bu tür mesajların parçalanması söz konusu olmadığından yukarıdaki sorun yaşanmaz. Bu tür mesajlarda mesaj boyu 256 byte ya da daha kısa olmalıdır. Ve mesajlar hep aynı uzunlukta olmalıdır. Bağlantısız iletişim ortamında kullanılır. Yani socket dinleyen program accept komutu kullanmaz, sockete bilgi gönderen de connect komutunu kullanmaz. Burada yalnızlisten komutu vardır. Programlar karşılıklı "read" ve "write" komutu ile haberleşir. İletişim açısından çok güvenli bir socket haberleşmesi değildir. Daha güvenli ve bağlantılı iletişimde (connected) DATA GRAM mesajları, SOCK_SEQPACKET tipi socket'ler üzerinde iletilmelidir.
Bir bilgisayar içindeki programlar arası iletişim SOCK_RAW tipi socket ile kurulabilir. Bu tür socket'lerde Data Gram tipi mesajlar iletilir.
linux ileri seviye  kullan??arTCP/IP İletişim Programları Mantığı
Bir sistemde TCP/IP program geliştirme modülleri varsa, programcının bu modülleri nasıl kullanacağı, kullanılmak istenilen socket türüne göre farklıdır. Eğer bağlantılı ve güvenli iletişimi içeren SOCK_STREAM kullanılıyorsa, yazılacak programın görevine göre iletişim komutları şöyle özetlenebilir :
İşveren (Client) Programı :
Bu program hangi bilgisayar ile bağlantı kuracağını belirledikten sonra socket komutu ile socket açar. Socket açıldıktan sonra ilk iş karşı taraftaki programla bağlantı kurmaktır. Bağlantı connect komutu ile kurulur. Bundan sonra işlem, mesaj gönderme ve cevap alma olarak devam eder. İşlem bittiğinde close komutu ile bağlantı kesilir.
İşgören Programı :
İşgören programı hangi bilgisayara hangi TCP portundan bilgi geleceğini bilmelidir. İşgören program her zaman bir TCP protunu dinler. İşgören programın dinlediği port birden çok IP adresi bulunan bir bilgisayarda bulunabilir. Bu durumda sunucu program yalnız bir bilgisayara gelen mesajları dinleyebilir. İstenirse sunucu program o bilgisayar gelen tüm mesajları da dinleyebilir.
İşgören program once socket komutu ile kullanacağı socket'i açmalıdır. İşgören programın bir porttan gelen mesajları dinlemesi icin bind komutunu başlatmış olması gerekir. listen komutuyla sunucu program, ilgili portu dinleyeceğini söyler. Bundan sonraki adım porttan bağlantı beklemektir. Porttan accept komutu ile bağlantı beklenir.
Porttan bağlantı mesajı geldiğinde sunucu program hemen kendini kopyalamalı, kopyalardan biri bağlantı kuran programla bilgi alış verişine başlarken diğer kopya yeni gelecek bağlantılar için portu dinlemeye devam etmelidir.
Mesaj alış verişi biten kopya bağlantı kapandığında çalışmasına son verir. Port dinleyen program bağlantı talebinin sayısına ve belleğin büyüklüğüne bağımlı olarak aynı anda birden çok kopya üretebilir ve aynı anda birden çok bağlantıya hizmet verebilir.
TCP/IP Komutları
gethostbyname : Bu komut verilen bir bilgisayar adına ilişkin yapı tanımını döndürür. Bu yapı tanımında bilgisayarın adresi ve TCP için kullanılan protokolun tanımı vardır. Bu komut kullanıldığında yazılan program INTRANET ya da INTERNET ortamında sorunsuz çalışır. Çünkü kullanılacak bilgisayar ilişkin yapı sistemdeki diğer programlar ve varsa name server tarafından hazırlanır.
socket : Bu komut iletişim için gerekli uç noktayı programa tanıtmak için kullanılır. Çeşitli socket kavramları aşağıda kısaca acıklanmıştır :

·        SOCK_STREAM : Sıralanmış ve iki yönlü bağlantı sonrası kullanılabilecek güvenli byte dizileri için geçerli bir socket türüdür.

·        SOCK_DGRAM : Kısa ve Sabit uzunluklu bağlantısız mesaj trafiğine elverişli, datagram tipi, çok güvenli olmayan bir socket türüdür.

·        SOCK_RAW : Bir bilgisayar içindeki iletişim için kullanılır. Belitilen (ya da adlandırılmış) sendkomutları için DATAGRAM göndermekte kullanılır. UNIZ ortamında yalnız super-kullanıcı (root) bu tür socket'leri kullanabilir.

·        SOCK_SEQPACKET : Bu tür socket datagram tipi kısa ve değişmez boylu mesajları bağlantıdan sonra kullanmaya yarar. Güvenli iletişim için gereklidir.
bind : Bu komut bir socket'i bir adrese bağlamak için kullanılır. Bu adres ya yerel bilgisayar adresi, ya da sıfır (0.0.0.0) adresi'dir. Bind komutu öncesinde socket komutu ile socket tanımlanmış olmalıdır.
listen : Bu komut gelen bağlantıları beklemek ve aynı anda gelen bağlantı isteklerini kuyruklamak için kullanılır. Bu komutta kaç tane isteğin kuruklanacağı da belirtilir. Bind komutundan sonra kullanılır.
accept : Bu komut ile socket'e gelecek bağlantı isteği beklenir. Bu komuttan önce socket komutu ile tanım yapılmış olmalı, bind komutu ile socket bir adrese bağlanmış olmalı ve listen komutu ile kuyruk boyu tanımlanmış olmalıdır. Bind, listen ve accept komutları hep bağlantı bekleyen program tarafından kullanılır. Diğer bir deyimle sunucu (iş gören) programı bu komutları kullanır.
connect : Bu komut, işveren programın socket tanımından sonra kullandığı komut olup, karşı tarafta bağlantı bekleyen programa, bağlantı isteğini iletmek için kullanılır. Eğer bağlantı bekleyen program çalışmıyorsa connect komutu hatalı bir biçimde sonlanır. Connect komutu ile accept komutu karşılıklı çalışan komutlardır.
write : Bağlantı kurulduktan sonra uygulama protokolu içinde hangi program bilgi gönderecekse "write" komutunu kullanırken karşı program "read" komutu ile gelecek bilgiyi bekler. Tüm iletişim programlarındaki genel kural ışığında "write" komutunu kullanan program mesajın gidip gitmediğini ancak karşı taraftan bir cevap aldığında anlar. Bu cevaba biz uygulama adımında "acknowledge" deriz. Yani, "write" komutunu kullanan bir program bu komutun peşinden "read" komutunu kullanarak karşı taraftaki programdan cevap bekler. Cevap alındıktan sonra yeni bir "write" komutu gönderilir. Ancak listen komutunda mesaj kuyruklama olanağı olduğundan uygulama sırasında her write komutundan sonra read beklemek aradaki iletişim hızını yavaşlatacağından, belirli sayıda "write" komutundan sonra bir kez "read" kullanmak iletişimi hızlandırır. Bu tür uygulamaya "windowing" adı verilmektedir.
Örneğin her yedi "write" komutundan sonra bir kez "read" komutu ile cevap beklemek, cevap geldiğinde yedi mesajın da karşı taraftaki program tarafından doğru alındığını belirttiği varsayılırsa gönderen program mesaj alındı yanıtını gönderilen her mesajdan sonra değil de yedi mesajdan sonra alması işlemi hızlandırır. Ancak cevap gelmemiş ise gönderen program aynı mesajları tekrar göndermek durumundadır. Çünkü karşı tarafın ne kadar mesajı aldığı bilinmemektedir. Bu nedenle "windowing" karvarı bozuk hatlarda iletişimi hızlandıracağına yavaşlatabilir. Dinamik "windowing" kullanmak, tekrarların sayısına göre "windowing" katsayısını değiştirmek iletişim programları açısından en olumlu ve verimli kullanım biçimidir.
select : read komutu karşı taraftan cevap gelinceye kadar sonsuz bu komutta bekleyen bir yapıya sahiptir. Bu ise iletişim açısından sakıncalıdır. En uygun yöntem belirli bir sürede karşı taraftan cevap gelmeyince "zaman aşımı" olduğunu varsaymak ve iletişimin aksadığına karar vermiş olmaktır. Zaman aşımını sağlamanın bir yöntemi select komutunu kullanmaktır. Select komutu yalnız zaman aşımını belirlemek için kullanılmaz. Aynı anda birden çok socket ya da seri uçtan hangisinden mesaj geldi ise onu algılamaya da yarar.
Bu özelliği ile select komutu, UNIX ortamında "Interrupt" bekleme işlemi gibi kullanılmış olur. Select komutu ile beraber kullanılan macro'lar aracılığı ile mesaj beklenecek socket ve seri uçlar önce bu komutun "Interrupt" vektörüne tanıtılır. Daha sonra bekleme süresi saptanır. Komut çalışmaya başladığında bekleme süresi içinde hangi socketten cevap geldi ise onun bilgisini programa iletir. Eğer hiç cevap gelmemiş ise komut programa "zaman aşımını" döndürür. Böylece select komutu ile bir program, birden çok socketten mesaj bekleyebilir ve bunun için socketler arasında "poll" işlemi yapmamış olur. Bilindiği gibi "polling" işletim sistemine ve işlemciye gereksiz işlem yükü getirmektedir. Sistemin verimliliği "poll" yapan programlar yüzünden azalabilir.
read : Select komutundan hemen sonra kullanılırsa sockette bekleyen mesajın okunması için gerekli olan komuttur. Bu biçimi ile kullanılınca iletişimin aksaması durumunda bile programın asılı kalması önlenmiş olur. Select kullanılmadan doğrudan "read" komutu kullanılmış ise program karşı taraftan mesaj gelmeden bir sonraki konuma geçemez. Bu şekilde read komutuna asılı kalan programlar ancak "kill" komutu ile dışarıdan yapılacak girişimle durdurulabilir.
close : Bu komut açılmış bir socket'i kapatmak icin kullanılır. Eğer program son bulmazsa ve close komutu kullanılmazsa, karsi taraf bağlantıyı kesse bile, socket kullanımda kalır, ancak program son bulunca serbest bırakılır.
PROGRAMLAMA 
SOCKET NEDIR?
---------------------
Diger programlarla konu$abilmek icin bir yoldur(ya da IPC=Interprocess communication'nin temel ta$idir).
Bu i$ icin standart file descriptor'leri kullanilir.File descriptor'ler, int turunden olan temel I/O
object'leridir.Detaylari sonra orneklerle goreceksiniz.
Genel olarak programcilar icin ba$vurulan 3 tur socket vardir: (hepsi bu 3 tane degil, bizim de ilgileneceklerimiz bunlar)
1- stream socket (SPX) (SOCK_STREAM)
telnet gibi, guvenli(o anlamda guvenli degil), cift yonlu, kontrollu paketler.
TCP(Transmission Control Protocol) kullanir.
Paketler 2 yonludur, eger A,B,C harflerini gonderirseniz kar$i taraf da A,B,C sirasiyla alir.
www browserlarinin kullandigi HTTP(hyper text transfer protocol) protocolu de stream turunden socket kullanirlar.
ornegin bir adrese telnet adres port:80 yapip GET pagename yaparsaniz
HTML(hyper text mark-up language) text olarak aynen size gelir gibi gibi.
2- datagram socket (IPX) (SOCK_DGRAM)
paket sirasi kari$ik olabilir, bilgi aki$i TCP gibi guvenli olmayabilir.
paketi gonderirsiniz, belki gitmeyebilir(karsi taraf ACK gonderene kadar).Giden paketler de sirali gitmeyebilir.
tftp,bootp,windows'taki realplayer ya da bir cok trojan bunu kullaniyor.
UDP(User datagram protocol) kullanir.
3- raw socket (SOCK_RAW)
(bir cok paket turunu degerlendirmek icin ya da ornegin birden cok protocole ayni zamanda eri$mek icin kullanilir)
bunlarin her birine ornek a$agida var.gelecegiz.

Simdi. ilk basta acayip gelebilecek fakat programlarimizda kullanacagimiz birkac ozellige bakalim.
Diger detaylari ornek programlarin icinde anlatmaya calistim. Please inspect them olayi ;P
Burada bahsedilmeyenlerin detaylarini nerede bulacaksin? cevap: internet ;)

SOCKET() : File Descriptor Tanimlayalim
-----------------------------------------------------
evet..yanli$ okumadin..unix aleminde aslinda her $ey bir file'dir ;)
tipki dosya i$lemleri gibi, socket'ler de aslinda bir tur file'dir.
------------------------------------------------------
#include
#include
int socket(int domain, int type, int protocol);
domain: AF_INET
type: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW gibi turlerden biri olacak.
protocol: $imdilik 0(sifir) olsun.daha sonra bununla orneklerde goreceksin.
$imdi, programlarimiz icin gerekli olabilecek struct'lara ornek olsun diyerek bakalim.
---------------------------------------------------------------------------
struct sockaddr {
unsigned short sa_family; /* addres turu, AF_xxx */
char sa_data[14]; /* 14 bytelik protocol addresi */
};
---------------------------------------------------------------------------
bu structure, bir cok turden socket icin socket adreslerini tutar.
sa_family : AF_INET gibi.
sa_data :socket icin destination adresi ve port noyu icerir.
programcilar, i$i internet tarafina ta$imak icin $u structure'i yazmi$lar:
---------------------------------------------------------------------------
struct sockaddr_in {
short int sin_family; /* Addres turu */
unsigned short int sin_port; /* Port no */
struct in_addr sin_addr; /* Internet addresi */
unsigned char sin_zero[8]; /* struct sockaddr ile ayni buyuklukte */
};
---------------------------------------------------------------------------
bunlari birazdan kullanacagiz, hepsi butunle$ecek.biraz sabir.
baska structure yok mu? var ..
diger structure'larin kullanimlarini ornekteki dosyalardan bakabilirsiniz.
tum structure'lar o kadar mi? hayir..senin Linux'ta hepsinin detaylari var..bkz..*.h files gibi.
BIND() : socketi bir porta baglayalim.
---------------------------------------------
Bir socketimiz olduktan sonra baglanti icin bir port belirlemeliyiz(stream.udp).
#include
#include
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
sockfd: yukarida bahsettigimiz socket file desciptor.
struct sockaddr *my_addr : port ve IP adresimizi belirtecek bolum.
addrlen: sockaddr buyuklugu,basitce $unu kullan: sizeof(struct sockaddr)
ORNEKLER : Vakit geldi.
---------------------------------
bu programlari denedikten sonra kurcalayabilirsin..al hepsi senin olsun ;)
internette artik search engine'lerdeki kutulara
"socket programming" and linux
gibi yazmanin zamani geldi de mi?
NOT: ASAGIDAKI PRGLARDA COMPILE SIRASINDA HATA VERIRSE : MAIL TO ME PLEASE.
buraya aktardiktan sonra biraz daha elledim orasina burasina, ondan diyorum.
PRG'LARIN YAZIM $EKLI C PRG YAZMA ETIGINE UYMUYOR CUNKU COPY-PASTE YAPTIM.
KUSURA BAKMAYIN KIZLAR ;)

1- ornek1-tcp.c dosyasina bakiniz,inceleyiniz.Orada detayli aciklamalar mevcut.
2- ornek2-udp.c dosyasina bakiniz,inceleyiniz.Orada detayli aciklamalar mevcut.
3- portdancer.c : daha tamamlanmamis hali..fakat is goruyor. calismayan send message kismini gordun mu? ;)

***************************************CUT HERE-TOP OF 1ST MODEL PRG*****
/*
tcp detector
by intruder.-tH3 3Lus1v3
a member of www.trscene.org
regardz to ALL babez.
bu prg, www.trscene.org ziyaretcilerine Linux socket programming
temellerini anlatabilmek icin ornek olarak yazilmistir.
degistirilir, baska formlara getirilebilir vs vs.
tamamiyla prototip,model,kaLIp olarak dusunebilirsiniz.
bunun ne yaptigini anlamak icin calistir...
sonra kendine
telnet 127.0.0.1 portno
yapabilirsin.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define kuyruk 10 /* kuyrukta kac guncel baglanti kalacak? 10 diyelim no prob. */
int main(int argc, char *argv[])
{
int sockfd, new_fd; /* socket degiskenlerimiz */
struct sockaddr_in my_addr; /* kendi adres bilgimiz */
struct sockaddr_in their_addr; /* client'in adres bilgisi */
/* biraz degisken tanimlayalim, lazim falan olur ;) */
int sin_size;
char laf, *mesaj;
int uzunluk,gidenbyte;
struct hostent *h; /* gethostname icin */
char *hostname; /* I love pointers ;P */
int pid; /*konuyla pek ilgisi yok ama, server tarafindaki pid nosu.*/
char *mesaj2[30];
int i;
if (argc<2)
{
printf("\nUsage: %s portnumber\n",argv[0]);
printf("\n");
return(-1);
}
printf("\nNow,dancing with port %s is active.Waiting for a connection.\n",argv[1]);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
/* her zaman error check yapmaliyiz ! sence neden ? */
my_addr.sin_family = AF_INET; /* cinsimizi belirleyelim */
my_addr.sin_port = htons(atoi(argv[1]));
/* portumuzu belirleyelim .htons(5555) gibi sabit de yapabiliriz.
burada kullanicinin girdigi deger ataniyor. */
my_addr.sin_addr.s_addr = INADDR_ANY;
/* kendi IP'miz olsun bu tabii ki.
eger IP'mizi biliyorsak ya da sabitse ornegin:
my_addr.sin_addr.s_addr ="199.99.125.63" */
bzero(&(my_addr.sin_zero), 8);
/* struct'in kalan kismini 0'layalim.bunu kural olarak gor,
$imdilik aynen kullan.ihmal de etme. */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
{
perror("bind");
exit(1);
}
/* porta baglama sirasinda hata olu$tu mu kontrol ettik.Eger hata ol$ursa program
hemen kapaniyor.Eger hatalari kontrol etmezsek 'core dumped' gibi moral bozucu
ve beklenmedik anda gocen programlarimiz olur.*/
if (listen(sockfd, kuyruk) == -1) {
perror("listen");
exit(1);
}
/* listeni kontrol ettirdik.aynen kullan */
while(1) { /* ana accept() loop'umuz */
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
continue;
}
printf("\nwarning....: %s\n",inet_ntoa(their_addr.sin_addr));
/* bi takim paket belirleme numuneleri vs vs..alternative'leri de izle */
hostname=inet_ntoa(their_addr.sin_addr);
/* compile sirasindaki pointer warning buradan kaynaklaniyor..
tur donu$umunu kontrolsuz yaptim ondan oluyor.ignore it ;P */
if ((h=gethostbyname(hostname))==NULL)
{
herror("gethostbyname");
exit(1);
}
printf("hostname-1= : %s\n",hostname);
printf("hostname-2 : %s\n", h->h_name);
printf("IP : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr)));
pid=getpid();
printf("Server side PID: %d\n",pid);
printf("Internet address is %s\n", inet_ntoa(their_addr.sin_addr.s_addr));
printf("Server side port number is %d\n", ntohs(my_addr.sin_port));
printf("Client side port number is %d\n", ntohs(their_addr.sin_port));
printf("Internet family ID is %d\n", their_addr.sin_family);

mesaj="yew are detected when performing some scan job.
\nI can see you babe.\n";
if (!fork()) { /* bu bizim child process */
if (send(new_fd, "oh yeah..cool ha?\n", 18, 0) == -1)
perror("?\n");
/* oradaki 18 mesajin uzunlugu kadar.say istersen ;) aslinda,
sizeof kullanmak daha mantikli degil mi? her seferinde byte mi sayacagiz.*/
/* send mesaj ornegi-mesaj */
uzunluk=strlen(mesaj);
gidenbyte=send(new_fd,mesaj,uzunluk,0);
/* baska bi sekilde mesaj gonderme ornegi-mesaj2 : an array is wife of a pointer ;P*/
for (i=0;i<21;++i)
{
mesaj2[i]=".\n"; /* tum elemanlari . ile doldurduk garip
karakterler gitmesin diye */
}
mesaj2[1]="\n";
mesaj2[2]="ok1\n";
mesaj2[3]="ok2\n";
/* dizinin kalan kismini yazmiyorum..ornekti bu..sen doldur istersen kalan kisim . olarak gidecek */
/* simdi olusturdugumuz mesaj2'yi gonderelim */
for (i=0;i<5;++i)
{
gidenbyte=send(new_fd,mesaj2[i],strlen(mesaj2[i]),0);
}
/*bu programi calistir..sonra kendine telnet yap sectigin porttan.
neyin gittigini daha iyi gorursun. */
close(new_fd);
exit(0);
}
close(new_fd); /* buna artik ihtiyac yok */
while(waitpid(-1,NULL,WNOHANG) > 0); /* child process'i de temizle */
}
} /* main function ended*/
***************************************CUT HERE-BOTTOM OF 1ST MODEL PRG*****
***************************************CUT HERE-TOP OF 2nd MODEL PRG*****
/*
udp detector
by intruder.-tH3 3Lus1v3
a member of www.trscene.org
regardz to ALL babez.
bu prg, www.trscene.org ziyaretcilerine Linux socket programming
temellerini anlatabilmek icin ornek olarak yazilmistir.
degistirilir, baska formlara getirilebilir vs vs.
tamamiyla prototip,model,kaLIp olarak dusunebilirsiniz.
bunun ne yaptigini anlamak icin calistirirken portno olarak 31337 kullan.
sonra bounix gibi bo clientindan kendine baglanmaya cali$ ya da
inetteki arkada$in windowstan denesin.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define kuyruk 10 /* kuyrukta kac guncel baglanti kalacak? 10 diyelim no prob. */
#define MAXBUFLEN 100
int main(int argc, char *argv[])
{
int sockfd, new_fd; /* socket degiskenlerimiz */
struct sockaddr_in my_addr; /* kendi adres bilgimiz */
struct sockaddr_in their_addr; /* client'in adres bilgisi */
/* biraz degisken tanimlayalim, lazim falan olur ;) */
int sin_size;
int uzunluk,gidenbyte;
struct hostent *h; /* gethostname icin */
char *hostname; /* I love pointers */
int pid;
int addr_len,numbytes;
char buf[MAXBUFLEN];
if (argc<2)
{
printf("\nUsage: %s portnumber\n",argv[0]);
printf("\n");
return(-1);
}
printf("\nNow,dancing with port %s is active.Waiting for an UDP connection.\n",argv[1]);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
my_addr.sin_family = AF_INET; /* cinsimizi belirleyelim */
my_addr.sin_port = htons(atoi(argv[1]));/* portumuzu belirleyelim */
my_addr.sin_addr.s_addr = INADDR_ANY; /* kendi IP'miz olsun bu tabii ki */
bzero(&(my_addr.sin_zero), 8); /* struct'in kalan kismini 0'layalim */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(1);
}

while(1)
{
addr_len = sizeof(struct sockaddr);
if ((numbytes=recvfrom(sockfd, buf, MAXBUFLEN, 0, \
(struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}
printf("got packet from %s\n",inet_ntoa(their_addr.sin_addr));
printf("packet is %d bytes long\n",numbytes);
buf[numbytes] = '\0';
printf("packet contains \"%s\"\n",buf);
/* bi takim belirleme numuneleri vs vs..alternative'leri de izle */
hostname=inet_ntoa(their_addr.sin_addr);
/* compile sirasindaki pointer warning buradan kaynaklaniyor..ignore it ;P */
if ((h=gethostbyname(hostname))==NULL)
{
herror("gethostbyname");
exit(1);
}
printf("hostname-1= : %s\n",hostname);
printf("hostname-2 : %s\n", h->h_name);
printf("IP : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr)));
pid=getpid();
printf("Server side PID: %d\n",pid);
printf("Internet address is %s\n", inet_ntoa(their_addr.sin_addr.s_addr));
printf("Server side port number is %d\n", ntohs(my_addr.sin_port));
printf("Client side port number is %d\n", ntohs(their_addr.sin_port));
printf("Internet family ID is %d\n", their_addr.sin_family);
printf("----------------------\n\n");
} /* while ended */
close(sockfd);
} /*main fuction ended */
***************************************CUT HERE-BOTTOM OF 2nd MODEL PRG*****
***************************************CUT HERE-TOP OF 3rd MODEL PRG*****
/*
portdancer.c
by intruder.-tH3 3Lus1v3
regardz to ALL babez.
anoher derivation of miplog for special purposes
*/
/* asagidaki include header'larinin sayisi gozunu korkutmasin..uzerinde oynadigim ve
burada bazi bolumleri cikarilmis yerler vardi..ayiklamaya ugrasmadim..aynen kullanabilirsin..zarari yok.*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

int main(int argc, char *argv[])
{
fd_set set;
int TCPfd, ICMPfd, UDPfd;
int int_of_send;
int pid;
char *msg;
struct ippkt_tcp
{
struct iphdr ip;
struct tcphdr tcp;
char buffer[10000];
}pkt_tcp;
struct ippkt_icmp
{
struct iphdr ip;
struct icmphdr icmp;
char buffer[10000];
}pkt_icmp;
struct ippkt_udp
{
struct iphdr ip;
struct udphdr udp;
char buffer[10000];
}pkt_udp;
struct servent *se;
struct in_addr i;
struct hostent *he;

if (argc<2)
{
printf("\n\n",argv[0]);
printf("\n");
/*return(-1);*/
}
printf("\nNow,dancing mode with ports is active.\nWaiting for a connection...\n",argv[1]);
printf("Server side pid : %d\n",getpid());
/* 1 defaya mahsus..affet..;P */
TCPfd=socket(AF_INET, SOCK_RAW, IPPROTO_TCP); /* tcp 6 */
ICMPfd=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); /* icmp 1 */
UDPfd=socket(AF_INET, SOCK_RAW, IPPROTO_UDP); /* udp 17*/

while (1)
{
FD_ZERO(&set);
FD_SET(TCPfd,&set);
FD_SET(ICMPfd,&set);
FD_SET(UDPfd,&set);
select(FD_SETSIZE, &set, NULL, NULL, NULL);
/* TCP CONNECTION DETECTED */
if (FD_ISSET(TCPfd,&set))
{
read(TCPfd, (struct ippkt_tcp *)&pkt_tcp,9999);
se=getservbyport(pkt_tcp.tcp.dest, "tcp");
i.s_addr=pkt_tcp.ip.saddr;
he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET);
if(se == NULL) printf("TCP-1, port: %d--", ntohs(pkt_tcp.tcp.dest));
else printf("TCP-2,port:%s--",se->s_name);
/* TCP-1: telnet gibi...TCP-2:rlogin gibi */
printf("from :%s--",he->h_name);
printf("IP:%s\n",inet_ntoa(i));
printf("address type:%d--",he->h_addrtype);
printf("address length: %d\n",he->h_length);
/* SEND MESSAGE TO LEANOV */
/*msg="hi babe";
int_of_send=send(TCPfd,msg,7,0);
int_of_send=write(TCPfd,"hi babex",9999);
*/
}

/* ICMP CONNECTION DETECTED */
if (FD_ISSET(ICMPfd,&set))
{
printf("ICMP connection detected.\n");
read(ICMPfd, (struct ippkt_icmp *)&pkt_icmp, 9999);
i.s_addr=pkt_icmp.ip.saddr;
he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET);
printf("from :%s--",he->h_name);
printf("IP:%s\n",inet_ntoa(i));
printf("address type:%d--",he->h_addrtype);
printf("address length: %d\n",he->h_length);
switch(pkt_icmp.icmp.type) {
case ICMP_DEST_UNREACH :
printf("Destination unreachable\n");
break;
case ICMP_SOURCE_QUENCH :
printf("source quench\n");
break;
case ICMP_REDIRECT :
printf("source route\n");
break;
case ICMP_ECHO :
printf("Ordinary ping\n");
break;
case ICMP_INFO_REQUEST:
printf("info request\n");
/* buradaki ICMP paket kontrol tiplerini cogaltabilirsin.
bkz. senin include'daki *.h dosyalarindan birisinde bunun tam listesi var. */
break;
} /* switch ended */
}
/* UDP CONNECTION DETECTED */
if (FD_ISSET(UDPfd,&set))
{
printf("UDP connection detected.\n");
read(UDPfd, (struct ippkt_udp *)&pkt_udp,9999);
i.s_addr=pkt_udp.ip.saddr;
he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET);
se=getservbyport(pkt_udp.udp.dest, "udp");
printf("UDP, port: %d", ntohs(pkt_udp.udp.dest));
printf("from :%s--",he->h_name);
printf("IP:%s\n",inet_ntoa(i));
printf("address type:%d--",he->h_addrtype);
printf("address length: %d\n",he->h_length);

}
FD_ZERO(&set);
FD_CLR(TCPfd,&set);
TCPfd=socket(AF_INET, SOCK_RAW, IPPROTO_TCP); /* tcp 6 */
ICMPfd=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); /* icmp 1 */
UDPfd=socket(AF_INET, SOCK_RAW, IPPROTO_UDP); /* udp 17*/
} /* while ended */
printf("flag.. final one");
} /*end of main(..) ;P */
***************************************CUT HERE-BOTTOM OF 3rd MODEL PRG*****

TCP/IP PROGRAMLARI

  




 

ÖRNEK CLIENT PROGRAMI

Bu program işgören (Server) bilgisayarda bulunan programla iletişim kurar ve mesaj gönderip, bu mesajın yanıtını bekler. Program işlemin bittiğini "son" değeri göndererek işgören programa bildirir. İki program arasındaki iletişim, "socket" kavramı ile kurulur. Client, "socket" açtıktan sonra "socket"i işgören programın adresine "connect" komutu ile bağlar. Daha sonra bu socket'e "write" komutu ile mesaj gönderir, "read" komutu ile gelen mesajı okur. İşlem bittiğinde işgören programa "son" mesajı gönderilir ve "socket" kapatılır.
Bu programda, hata kontrol adımları programın boyunu büyütmemek ve mantığını bozmamak için çıkarılmıştır. Programın boyu ne kadar kısa olursa o kadar kolay anlaşılır. İletişim protokolu olarak TCP/IP yerine AF_UNIX kullanılmıştır. Burada işgören program ve müşteri aynı bilgisayarda çalışır. TCP/IP kullanıldığında önce, "gethostbyname" komutu ile adres ve kullanılan protocol belirlenir. Daha sonra "getservbyname" komutu ile TCP/IP servisi için port numarası belirlenir "sockaddr_in" yapısı bu bilgilerle doldurulur. En son "connect" işlemi çalıştırılır.
   #include 
   #include 
   #include 
   
   main()
   {
   struct sockaddr_un to;
   int  s;
   int  tolen, len, n, maxlen;
   char msg[512], inbuf[512];
   maxlen = 512;
   
   /********* socket acma islemi ***********/
   s = socket(AF_UNIX,SOCK_STREAM,0);
   
   /********* isgoren programa baglanma *********/
   to.sun_family = AF_UNIX;       /* socket protocol ailesi */
   strcpy(to.sun_path,"address"); /* socket adresi */
   tolen = sizeof(to.sun_family) + sizeof(to.sun_path);
   connect(s,(struct sockaddr *) &to, tolen);
   
   memset(msg,'\0',maxlen);
   while(strncmp(msg,"son",3)) {  /* gonderilen mesaj son degilse devam et */
       printf("mesajı girin :");
       gets(msg);
       len = strlen(msg);
       write(s,msg,len);          /* mesaj gonderme */
       n = read(s,inbuf,maxlen);  /* cevap beklemede okunan n byte olur */
       inbuf[n] = '\0';
       puts(inbuf);               /* gelen cevabi ekrana yazma */
       }
   close(s);                      /* islem bitti socket kapatildi */
   }

ÖRNEK SERVER PROGRAMI

Server program, Client programlardan gelen bilgileri alır ekrana yazar sonra Client programa mesajın alındığını bildirir. Server, açılan bir "socket"i "bind" komutu ile adrese bağlar ve client bağlantıları için "listen" konumuna geçer. Client'tan gelen "connect" mesajlarını algılamak için "accept" komutu kullanılır. Server her zaman bir tane "accept" komutunda boş beklerken diğer kopya, bağlantı kurulmuş "socket" ten okuma yapar, okunan bilgiye cevap verir. Okunan mesaj "son" ise bu kopya işlemini bitirir.

   #include 
   #include 
   #include 
   #include 
   
   jmp_buf jbuf;
   
   void bitti()
   {
   longjmp(jbuf,-1);
   }
   
   main()
   {
   struct sockaddr_un from;
   int  s, s1;
   int  fromlen, len, n, maxlen, maxqueue;
   char inbuf[512];
   maxlen = 512;
   maxqueue = 10;
 
   signal(SIGTERM, bitti);
   if(setjmp(jbuf) != -1) {
       /********* socket acma islemi ***********/
       s = socket(AF_UNIX,SOCK_STREAM,0);
 
       /********* sockete adres baglama **********/
       from.sun_family = AF_UNIX;       /* socket protocol ailesi */
       strcpy(from.sun_path,"address"); /* socket adresi */
       fromlen = sizeof(from.sun_family) + sizeof(from.sun_path);
       bind(s,(struct sockaddr *) &from , fromlen);
   
       /********* bekleme konumuna alma **********/
       listen(s,maxqueue);
   
       /********* connect bekleme ****************/
       /* client program connect bekleyen yoksa hata verir
          bu nedenle server connect bekler durumda olmalidir. */
          
       do {
          s1 = accept(s,(struct sockaddr *) &from , fromlen);
          
          /**** connect geldi fork ile bir kopya baslat *****/
          /* bir baska client connect gonderdiginde, server 
             accept komutunda degisle, bu komuta gelinceye kadar
             beklemektedir. Bunun icin yeni bir server
             kopyasi calismali ve connect beklemelidir. */
          if(fpid = fork()) {
              memset(inbuf,'\0',maxlen);
              while(strncmp(inbuf,"son",3)) {
                  /*** okumayi eski kopya yapar,
                       yeni kopya hala connect beklemektedir ****/
                  n = read(s1,inbuf,maxlen);
                  inbuf[n] = '\0';
                  /* gelen bilgiyi isleme alma */
                  puts(inbuf);
                  /* mesaj alindi bilgisini gonderme */
                  write(s1,"OK",2);
                  }
              }
          } while(fpid == 0);
      }
   if(fpid == 0) {
        /*** connect beklerken
             kill -15 ile server durdurulursa ****/
        close(s);
        unlink(from.sun_path);
        }
   else close(s1);
   }
Client programda olduğu gibi işgören program da AF_INET protokol ailesi ile kullanıldığında "gethostbyname" komutu ile yerel bilgisayarın adresi alınır. Daha sonra, "getservbyname" komutu ile INET servisinin port numarası alınır ve "sockaddr_in" yapısı bu bilgilerle doldurulur. Diğer komutlarda işlem akışı örnek programda anlatıldığı gibidir.


SDLC (Synchronous Data Link Communication)


GİRİŞ

SDLC protokolune göre SNA ortamında iki tip bilgisayar vardır. Bunlardan merkezdekine birincil bilgisayar, uzaktan bağlanana ise ikincil bilgisayar denir. Birincil bilgisayar kurulan iletişim yöntemini denetleyen bilgisayardır. Fiziksel birimler birbirleri ile iletişimi kurduktan sonra, her iki bilgisayarda yer alan mantıksal birimler birbirleri ile oturum başlatır. Her mantıksal birim karşısındaki mantıksal birimle başka birimlerden bağımsız oturum kurabilir. Bir hat üzerinde birden çok ikincil bilgisayar olabilir. Bu bilgisayarlar fiziksel birimlerdir. Aynı hat üzerindeki birden çok fiziksel birim C1, C2 gibi adreslerle birbirlerinden ayrılır. Aynı hattı paylaşımlı kullanırlar. Bir fiziksel bilgisayarın karşı tarafa bağlantısı için gereken SDLC komutları şöyledir :

SNRM
(Set Normal Response Mode)
İlk bağlantı kurulurken gönderilen paketleri karşı taraf aldığında gelen paket bu komutu içerir. RR (Read to Receive) : Her iki bilgisayar "Bekleme" konumunda iken veya gelen paket alındıktan sonra gönderilen boş pakettir. Bir paketin karşı taraftan alındığı, karşıdan gelen RR paketi ile anlaşılır.
ACTPU (Activate PU)
Birincil bilgisayar iikincil bilgisayarın fiziksel biriminin Aktif olmasını istemektedir. Aslında fiziksel bilgisayarın aktif duruma gelmesi demek SDLC protokolunda mesaj alış verişini her iki bilgisayarında başlatmış olması demektir.
DACTPU (Deactivate PU)
Fiziksel birimi kapat. Bu komut varsa oturumda olan mantıksal birimlerin oturumlarının da kapanmasına neden olur. Oturumda olsun olmasın tüm mantıksal birimler bu komutla "Deactive" konuma gecer.
Mantıksal birimlerin SDLC protokolunda kullandığı komutlar aşağıda açıklanmıştır.
ACTLU (Activate LU)
Birincil bilgisayarda karşı bilgisayarda bulunabilecek mantıksal birimler tanımlıdır. Bu komut mantıksal birimlerin ikincil bilgisayarda da tanımlı olup olmadığını anlamak için kullanılır. İkincil bilgisayar gelen her ACTLU komutuna, tanım varsa olumlu yanıt verir. Aksi halde DACTLU komutu ile yanıt verilir ve Birincil bilgisayar bu mantıksal birim ile bağlantı kurulamayacağını anlar.
XID (Exchange ID)
Her iki bilgisayar, birbirleri ile tanım alışverişinde bulunur. Max. Mesaj boyu ve bilgisayar tanımları gibi bilgiler bi komut ile bilgisayarlar arasında değiş tokuş yapılır.
INITSELF
Bu komut ile ilgili ayrıntılı bilgi protokol arayüzünde anlatılmıştır.
BIND
İki uygulama programının birbiri ile bağlantı kurması bu komut aracılığı ile yapılır. Kurulan bağlantıda kullanılan kalıp ve sistemlerin mesaj algılama biçimleri bu komut ile tanımlanır. Birincil bilgisayar komutun içeriğini belirtir, ikincil bilgisayar, bu komutu kabul ediyorsa olumlu cevap verir ve oturum kurulmuş olur. Komut kabul edilmiyorsa ikincil bilgisayar bağlantının kesilmesi için UNBIND gönderir.
SSNUM
(Set Sequence Number)
Oturum kurulduğunda paketlerde yer alan paket sıra numarası bu komu ile her iki bilgisayarda da ilk değerine getirilir.
SDT (Start Data Trafic)
Komut alış verişi tamamlandıktan sonra birincil bilgisayar, veri iletişiminin başlayabileceğini bu komut ile birdirir. Atrık bilgisayarlar uygulama programı bilgilerini birbirlerine gönderebilirler.
DACTLU (Deactivate LU)
Bu komut oturumun kapanması ve mantıksal birimin artık merkez tarafından tanınmadığının belirtilmesi anlamına gelir.



MAKE KOMUTU ve MAKEFILE

GENEL BİLGİLER
make komutu çalıştırıldığı directory'de makefile veya Makefile varsa burada belirtilen işlemleri yapar.make komutu makefile içindeki hedef tanımlara ulaşmak için tanımlanan bağımlılıkları da kullanarak belirtilendirectory'de bulunan tüm tarihi geçmiş kütüklerden liste oluşturur ve tanıma uygun işlemi yapar.
make programı tüm çevre (environment) tanımlarını okur. Boş olan tanımları dikkate almaz. "makefile" içindeki çevre değişkenlerine yapılan atamalar, bu değişkenlerin değerini değiştirir.
MAKEFLAGS isimli çevre değişkeni bu değişken "make" komutu için -f ve -p seçenekleri hariç, diğer komut seçeneklerini içerir. "make" programı bu değişkende tanımlanan seçeneklerle çalışır.
Seçenekler ne olursa olsun makefile içindeki $(MAKE), her koşulda çalıştırılır.
EKLEME KÜTÜKLERİ (INCLUDE FILES)
makefile içinde kullanılan include deyimi satırın başından başlar. Boşluk veya "tab" tuşundan sonrası kütük adı olarak kullanılır. "make" komutu include ile gösterilen kütüğü bulamaz ise "kütük bulunamadı" hatası verir.sinclude aynı amaç için kullanılır. Ancak kütük bulunamaz ise hata vermeden make işlemlere devam eder.
makefile "#!alternate_make" ile başlıyorsa, aynı çevre değişkenleri ile başka bir "make" kullanılır. #! satırında gerekiyorsa başka parametreler de tanımlanabilir. Bu satır makefile içinde tüm make komutlarından önce tanımlanmalıdır.
string1 = string2
gibi tanımlara macro tanımlar denir. macro adlarının ilk karakteri harf olmalıdır. Macro adlarında çoğu kez büyük harf kullanılır. macro adları içinde "._-+~" bulunabilir. macro tanımında string2 açıklama (comment) dışında satır sonu karakterine kadar olan herşeydir. $(string1) kullanılan her yerde string1 yerine string2değeri açılır.
$(string1[subst1=subst2])
biçimindeki tanımlarda seçenekli taşıma ve açma işlemi vardır. Macro içindeki subst1 bulunan her yeresubst2 değeri taşınır. Özel koşul olarak subst1 boş ise subst2 macronun sonuna eklenir.
MAKE İÇİNDEKİ (INTERNAL) MACRO TANIMLARI
$*
son eki kaldırılmış bağımlı kütük adlarını belirtir.
$@
geçerli hedef bilginin tüm adıdır. Açıkça belirtilmiş bağımlılık tanımlarında kullanılır.
$$@
$@ ile tanımlanmış geçerli hedef bilginin tüm adını gösterir. Örneğin :
cat dd: $$@.c
tanımında, make bu satırı cat.c ve dd.c olarak açar.
$<
yalnız .DEFAULT kuralı için geçerli açılımı yapar. Yani .c.o kuralı için :
.c.o :
cc -c -O $*.c
veya
.c.o :
cc -c -O $<
aynı amaçla kullanılabilir.
$?
makefile için açıkça tanımlanan kuralların açılımında kullanılır. Bu macro hedef kurala göre günü geçmiş bağımlılıkların listesini oluşturur ve doğal olarak bu modüller yenilenir.
$%
Eğer hedef arşiv kütüpanesi ise bu macro, herbir üyeyi
lib(file.o)
biçiminde açar. Bu macroda $@ lib olarak $% ise file.o olarak açılır.
Bu macroların sonuna D veya F eklenirse anlamları değişir. D eklenirse adlandıral macronun directory bölümü F eklenirse macronun kütük bölümü anlaşılır. Eğer $(@D) işleminde directory yoksa ./ açılan değer olur.
SON EKLER
Bazı adların bağımlı olduğu ön koşullar vardır. Örneğin .o her zaman .c ve .s gibi son eklere bağımlıdır. Eğer bu tür kütükleri günlemek için gerekli koşul makefile içinde yoksa veya kütük bulunamıyorsa, son ön koşuldan hedefi yaratmak için gereken derleme yapılır. Bu durumda make, son ekleri inceleyerek bağımlılık koşullarını belirler ve ilgili hedef kuralı bulur. Bu tür INTERNAL kuralları listelemek için
    make -p -f/dev/null
komut satırı kullanılır. Bağımlılık kuralları makefile içinde yeniden tanımlanabilir veya -r komut seçeneği ile tümüyle atlanabilir.
Yukarıdaki anlatımda (bağımlılık kuralları) eğer '~' kullanılırsa, make programı gerekli kaynak programı SCCS (Source Code Control System) altından alır. Yani .c~.o kuralı SCCS altındaki C kaynak programını .o kütük haline dönüştürür.
makefile .c şeklinde bir kural x.c den nasıl x elde edileceğini gösterir. Bu işlem bir kaynaktan hedef elde etmek için önemlidir (örneğin shell script veya C programları). Null Suffix kuralı, birden çok bağımlılık durumunda make tarafından dikkate alınmaz.
Sistemde kullanılacak başka son ekler .SUFFIXES listesinde belirtilir. Bu listede yer alan son ekler ön koşul sıralamasına göre yerleştirilmelidir. Daha önceki belirtilen komut satırı ile bu tür son ek listesi ve bağımlılıklar kullanılan sistemdeki varsayılan değerleri görmek için alınabilir.
Kullanıcılar makefile içinde
    prgm: a.o b.o
         cc a.o b.o -o prgm
    a.o b.o: incl.h
gibi kurallar tanımlayarak standard bağımlılıklara ekler yapabilirler.
kullanılabilecek macro tanımları :
    CFLAGS   cc için gereklidir
    LFLAGS   lex için gereklidir
    YFLAGS   yacc için gereklidir.
Bağımlılık ön koşulları makefile içinde kontrol edilebilir. .c son ekinden .o elde etmek için .c.o: kuralı tanımlanır. Burada bağımlılık belirtilmez. İçinde / olmayan ve . ile başlayan bir hedef her zaman bir kuralı belirtir, gerçek hedef değildir.
KITAPLIKLAR (LIBRARIES)
Eğer bir macro adı ve bağımlılık kuralında parantezler varsa buna arşiv kitaplığı denir. Yani lib(file.o) ve $(LIB)(file.o) içinde file.o olan arşiv kütüphanesini belirtir.
Arşiv kitaplığına ilişkin kurallar .XX.a tipindedir. Burada XX arsiv kitaplığı üyelerinin oluşturulduğu son ektir. XX arşiv üyeleri son ekinden farklı olmalıdır. Yani lib(file.o) açıkça file.o ya bağlı olamaz. Örnek
   lib: lib(file1.o) lib(file2.o) lib(file3.o)
   @echo lib is non up-to-date
   .c.a:
        $(cc) -c $(CFLAGS) $< $(AR)$(ARFLAGS)$@$*.o
        rm -f $*.o
Bu kural make içinde zaten hazır olarak vardır. Daha ilginç bir örnek :
   lib: lib(file1.o) lib(file2.o) lib(file3.o)
        $(CC) -c $(CFLAGS) $(?:.o=.c)
        $(AR) $(ARFLAGS) lib $?
        rm $? @echo lib is now up-to-date
   .c.a:;
Bu örnekte macro içinde yerine koyma kuralı kullanılır. $? lib içindeki kütüklerin listesidir. Yerine koyma kuralı tüm .c leri .o ya çevirir. Bu örnekteki .o.a:; makefile içinde kuralın kapatıldığını gösterir. Burada kullanılan noklaı virgül ile kuralın kapatılması sağlanır. Bu tür arşiv kitaplıklarında yaratma/günleme işlemi asm ve C dili karışımı kaynak programlar kullanıldığında çok yararlıdır ve işlemi hızlandırır.
PARALEL ÇALIŞTIRMA
make komutundaki -P seçeneği parelel çalıştırmayı başlatır. Bu işlem için make komutu önce tüm bağımlılıkları kaldırır ve sonuçta oluşan kümeleri aynı anda açar. Aynı anda yapılan işlem sayısı faktörü en çok iki olabilir. PARALLEL çevre değişkeni ile bu sayı değiştirilebilir.
  Örnek Makefile kütükleri :

SHELL = /bin/sh
MAKE = make
# Burada all ve install hedef tanımları include/printer.h kütüğüne
# bağımlıdır. make programı bu bağımlılığa göre src directory'si
# altındaki Makefile kütüğüne aynı parametrelerle bakar.
all install: include/printer.h
cd src; $(MAKE) $@
# bu tanımda printer.h kütüğünde yapılan bir değişiklik varsa
# configurasyon programı çalıştırılır. Bu program kullanılan
# UNIX sistemi özelliklerine göre yeni Makefile yaratır.
include/printer.h:
configure
clean:
cd src; $(MAKE) $@

# src/Makefile
DESTOWN = admin
DESTGRP = pamuk
DESTBIN = ../bin
DEFINES = -I../include -DUNIX -DAIX
CC = cc
CFLAGS = -g $(DEFINES)
LIBS = -lcurses -ltli_r
PROGRAMS = yazserv npbaslat sendmsg
SRCS = sendmsg.c pbaslat.c yazserv.c
HDRS = ../include/printer.h
YAZSRV_OBJS = yazserv.o
SNDMSG_OBJS = sendmsg.o
BASLAT_OBJS = pbaslat.o
.c.o:
$(CC) -c $(CFLAGS) $<
all: $(PROGRAMS)
yazserv: $(YAZSRV_OBJS)
$(CC) $(YAZSRV_OBJS) $(LIBS) -o $@
npbaslat: $(BASLAT_OBJS)
$(CC) $(BASLAT_OBJS) $(LIBS) -o $@
sendmsg: $(SNDMSG_OBJS)
$(CC) $(SNDMSG_OBJS) $(LIBS) -o $@
install: $(PROGRAMS)
cp $(PROGRAMS) $(DESTBIN)
cd $(DESTBIN) && strip $(PROGRAMS)
cd $(DESTBIN) && chmod 755 $(PROGRAMS)
cd $(DESTBIN) && chown $(DESTOWN):$(DESTGRP) $(PROGRAMS)
clean:
cd $(DESTBIN) && rm -f $(PROGRAMS)
-rm -f $(PROGRAMS) $(YAZSRV_OBJS) $(BASLAT_OBJS) $(SNDMSG_OBJS)
yazserv.o: $(HDRS)
sendmsg.o: $(HDRS)
pbaslat.o: $(HDRS)
  EK
MAKE KOMUTU VERI TABANI

# GNU Make version 3.74,
# by Richard Stallman and Roland McGrath.
# Copyright (C) 1988, 89, 90, 91, 92, 93, 94, 95
# Free Software Foundation, Inc.
# This is free software;
# see the source for copying conditions.
# There is NO warranty;
# not even for MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
# Variables
# default
F77 = $(FC)
# default
PREPROCESS.r = $(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F
# automatic
@F = $(notdir $@)
# environment
HOME = /u/ergun
# default
MAKE = $(MAKE_COMMAND)
# environment
LESSOPEN = |lesspipe.sh %s
# default
SUFFIXES := .out .a .ln .o .c .cc .C .p .f .F .r .y .l .s .S .mod .symi .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el
# default
COMPILE.r = $(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c
# default
LINK.F = $(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# default
LINK.s = $(CC) $(ASFLAGS) $(LDFLAGS) $(TARGET_MACH)
# environment
MAIL = /var/spool/mail/ergun
# environment
PWD = /u/ergun/ben/docs
# default
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
# default
TEXI2DVI = texi2dvi
# automatic
+F = $(notdir $+)
# default
COMPILE.f = $(FC) $(FFLAGS) $(TARGET_ARCH) -c
# environment
PS1 = %m:%~%#
# automatic
%F = $(notdir $%)
# default
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# default
CO = co
# automatic
?D = $(patsubst %/,%,$(dir $?))
# environment
_ = /usr/bin/make
# default
PREPROCESS.F = $(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F
# automatic

# default
M2C = m2c
# default
FC = f77
# default
CC = cc
# environment
MINICOM = -c on
# default
LINK.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)
# default
CXX = g++
# default
AR = ar
# default
CWEAVE = cweave
# environment
OPENWINHOME = /usr/openwin
# default
COMPILE.F = $(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# environment
USER = ergun
# automatic
*D = $(patsubst %/,%,$(dir $*))
# automatic
^D = $(patsubst %/,%,$(dir $^))
# default
COMPILE.s = $(AS) $(ASFLAGS) $(TARGET_MACH)
# makefile
SHELL = /bin/sh
# environment
MANPATH = /usr/local/man:/usr/man/preformat:/usr/man: /usr/X11/man:/usr/openwin/man
# default
YACC = yacc
# default
COMPILE.def = $(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH)
# default
LINK.C = $(LINK.cc)
# makefile
MAKEFLAGS = p
# default
LINK.p = $(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# default
OUTPUT_OPTION = -o $@
# default
MAKE_VERSION := 3.74
# default
PREPROCESS.S = $(CC) -E $(CPPFLAGS)
# environment
MAKELEVEL := 0
# environment
PS2 = >
# default
YACC.y = $(YACC) $(YFLAGS)
# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default
TANGLE = tangle
# default
CHECKOUT,v = $(patsubst $@-noexist,$(CO) $(COFLAGS) $< $@,
$(filter-out $@,$(firstword $(wildcard $@) $@-noexist)))
# default
LD = ld
# environment
MFLAGS = -p
# default
GET = get
# environment
ignoreeof = 10
# environment
HOSTNAME = napoleon.yerel.yore.com.tr
# default
COMPILE.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c
# default
PC = pc
# default
AS = as
# automatic
@D = $(patsubst %/,%,$(dir $@))
# environment
HZ = 100
# default
TEX = tex
# environment
TERM = linux
# environment
LOGNAME = ergun
# environment
SHLVL = 1
# environment
LESS = -MM
# default
COMPILE.C = $(COMPILE.cc)
# default
LINT = lint
# default
F77FLAGS = $(FFLAGS)
# default
COMPILE.p = $(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default
RM = rm -f
# automatic
+D = $(patsubst %/,%,$(dir $+))
# default
WEAVE = weave
# automatic
?F = $(notdir $?)
# automatic
%D = $(patsubst %/,%,$(dir $%))
# default
CPP = $(CC) -E
# automatic

# default
LEX = lex # default
LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# default
LEX.l = $(LEX) $(LFLAGS) -t
# default
COMPILE.mod = $(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH)
# default
ARFLAGS = rv
# automatic
*F = $(notdir $*)
# automatic
^F = $(notdir $^)
# default
LINT.c = $(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)
# default
LINK.r = $(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# environment
BULLDOZERLIB = /usr/local/lib/dozer-0.7.2b
# default
COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default
MAKEFILES :=
# default
CTANGLE = ctangle
# default
MAKE_COMMAND := make
# environment
PATH = /bin:/usr/bin:/usr/local/bin:/usr/X11/bin:/usr/andrew/bin: /usr/openwin/bin:/usr/games:.:/usr/local/bin/Thot/LINUX-ELF/bin:
# default
LINK.f = $(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# environment
LS_COLORS = no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35: bd=40;33;01:cd=40;33;01:ex=01;32:*.cmd=01;32:*.exe=01;32: *.com=01;32:*.btm=01;32:*.bat=01;32:*.tar=01;31:*.tgz=01;31: *.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31: *.gz=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35: *.xpm=01;35:*.tif=01;35:
# default
MAKEINFO = makeinfo
# 98 variables in 523 hash buckets.
# average of 0.2 variables per bucket, max 3 in one bucket.
# Directories
# SCCS: could not be stat'd.
# /dev/RCS: could not be stat'd.
# /dev (device 769, inode 4065): 1283 files, 42 impossibilities.
# RCS: could not be stat'd.
# /dev/SCCS: could not be stat'd.
# 1283 files, 42 impossibilities in 5 directories.
# Implicit Rules
%.out:
%.a:
%.ln:
%.o:
%: %.o
# commands to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.c:
%: %.c
# commands to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.ln: %.c
# commands to execute (built-in):
$(LINT.c) -C$* $<
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $< $(OUTPUT_OPTION)
%.cc:
%: %.cc
# commands to execute (built-in):
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.cc
# commands to execute (built-in):
$(COMPILE.cc) $< $(OUTPUT_OPTION)
%.C:
%: %.C
# commands to execute (built-in):
$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.C
# commands to execute (built-in):
$(COMPILE.C) $< $(OUTPUT_OPTION)
%.p:
%: %.p
# commands to execute (built-in):
$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.p
# commands to execute (built-in):
$(COMPILE.p) $< $(OUTPUT_OPTION)
%.f:
%: %.f
# commands to execute (built-in):
$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.f
# commands to execute (built-in):
$(COMPILE.f) $< $(OUTPUT_OPTION)
%.F:
%: %.F
# commands to execute (built-in):
$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.F
# commands to execute (built-in):
$(COMPILE.F) $< $(OUTPUT_OPTION)
%.f: %.F
# commands to execute (built-in):
$(PREPROCESS.F) $< $(OUTPUT_OPTION)
%.r:
%: %.r
# commands to execute (built-in):
$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.r
# commands to execute (built-in):
$(COMPILE.r) $< $(OUTPUT_OPTION)
%.f: %.r
# commands to execute (built-in):
$(PREPROCESS.r) $< $(OUTPUT_OPTION)
%.y:
%.ln: %.y
# commands to execute (built-in):
$(YACC.y) $<
$(LINT.c) -C$* y.tab.c
$(RM) y.tab.c
%.c: %.y
# commands to execute (built-in):
$(YACC.y) $<
mv -f y.tab.c $@
%.l:
%.ln: %.l
# commands to execute (built-in):
@$(RM) $*.c
$(LEX.l) $< > $*.c
$(LINT.c) -i $*.c -o $@
$(RM) $*.c
%.c: %.l
# commands to execute (built-in):
@$(RM) $@
$(LEX.l) $< > $@
%.r: %.l
# commands to execute (built-in):
$(LEX.l) $< > $@
mv -f lex.yy.r $@
%.s:
%: %.s
# commands to execute (built-in):
$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.s
# commands to execute (built-in):
$(COMPILE.s) -o $@ $<
%.S:
%: %.S
# commands to execute (built-in):
$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.S
# commands to execute (built-in):
$(COMPILE.S) -o $@ $<
%.s: %.S
# commands to execute (built-in):
$(PREPROCESS.S) $< > $@
%.mod:
%: %.mod
# commands to execute (built-in):
$(COMPILE.mod) -o $@ -e $@ $^
%.o: %.mod
# commands to execute (built-in):
$(COMPILE.mod) -o $@ $<
%.sym:
%.def:
%.sym: %.def
# commands to execute (built-in):
$(COMPILE.def) -o $@ $<
%.h:
%.info:
%.dvi:
%.tex:
%.dvi: %.tex
# commands to execute (built-in):
$(TEX) $<
%.texinfo:
%.info: %.texinfo
# commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
%.dvi: %.texinfo
# commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
%.texi:
%.info: %.texi
# commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
%.dvi: %.texi
# commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
%.txinfo:
%.info: %.txinfo
# commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
%.dvi: %.txinfo
# commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
%.w:
%.c: %.w
# commands to execute (built-in):
$(CTANGLE) $< - $@
%.tex: %.w
# commands to execute (built-in):
$(CWEAVE) $< - $@
%.ch:
%.web:
%.p: %.web
# commands to execute (built-in):
$(TANGLE) $<
%.tex: %.web
# commands to execute (built-in):
$(WEAVE) $<
%.sh:
%: %.sh
# commands to execute (built-in):
cat $< >$@
chmod a+x $@
%.elc:
%.el:
(%): %
# commands to execute (built-in):
$(AR) $(ARFLAGS) $@ $<
%.out: %
# commands to execute (built-in):
@rm -f $@
cp $< $@
%.c: %.w %.ch
# commands to execute (built-in):
$(CTANGLE) $^ $@
%.tex: %.w %.ch
# commands to execute (built-in):
$(CWEAVE) $^ $@
%:: %,v
# commands to execute (built-in):
+$(CHECKOUT,v)
%:: RCS/%,v
# commands to execute (built-in):
+$(CHECKOUT,v)
%:: s.%
# commands to execute (built-in):
$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<
%:: SCCS/s.%
# commands to execute (built-in):
$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<
# 82 implicit rules, 4 (4.9%) terminal.
# Files
# Not a target:
.c: # Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.texinfo.info:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
# Not a target:
.mod.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.mod) -o $@ $<
# Not a target:
.c.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.

# commands to execute (built-in):
$(COMPILE.c) $< $(OUTPUT_OPTION)
# Not a target:
.s:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.txinfo.dvi:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
# Not a target:
.DEFAULT:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.y.c:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(YACC.y) $<
mv -f y.tab.c $@
# Not a target:
.l:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.web.tex:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(WEAVE) $<
# Not a target:
.s.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.s) -o $@ $<
# Not a target:
.sym:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.texi:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.F.f:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(PREPROCESS.F) $< $(OUTPUT_OPTION)
# Not a target:
.dvi:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.web.p:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(TANGLE) $<
# Not a target:
.def:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.F:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.cc.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.cc) $< $(OUTPUT_OPTION)
# Not a target:
.S.s:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(PREPROCESS.S) $< > $@
# Not a target:
.ch:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.def.sym:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.def) -o $@ $<
# Not a target:
.F.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.F) $< $(OUTPUT_OPTION)
# Not a target:
.f:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.elc:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.y.ln:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(YACC.y) $<
$(LINT.c) -C$* y.tab.c
$(RM) y.tab.c
# Not a target:
.texi.dvi:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
# Not a target:
.el:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.texinfo.dvi:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
# Not a target:
/dev/null:
# Implicit rule search has been done.
# Last modified Mon Jul 18 02:46:18 1994 (774488778)
# File has been updated.
# Successfully updated.
# Not a target:
.SUFFIXES: .out .a .ln .o .c .cc .C .p .f .F .r .y .l .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.txinfo:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.p.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.p) $< $(OUTPUT_OPTION)
# Not a target:
.r.f:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(PREPROCESS.r) $< $(OUTPUT_OPTION)
# Not a target:
.w.tex:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(CWEAVE) $< - $@
# Not a target:
.txinfo.info:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
# Not a target:
.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.c.ln:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINT.c) -C$* $<
# Not a target:
.w:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.ln:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.l.r:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LEX.l) $< > $@
mv -f lex.yy.r $@
# Not a target:
.info:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.r.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.r) $< $(OUTPUT_OPTION)
# Not a target:
.h:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.C.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.C) $< $(OUTPUT_OPTION)
# Not a target:
.p:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.l.c:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
@$(RM) $@
$(LEX.l) $< > $@
# Not a target:
.sh:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
cat $< >$@
chmod a+x $@
# Not a target:
.web:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.out:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.cc:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.f.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.f) $< $(OUTPUT_OPTION)
# Not a target:
.texi.info:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
# Not a target:
.a:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.tex:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.l.ln:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
@$(RM) $*.c
$(LEX.l) $< > $*.c
$(LINT.c) -i $*.c -o $@
$(RM) $*.c
# Not a target:
.y:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.S.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.S) -o $@ $<
# Not a target:
.tex.dvi:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(TEX) $<
# Not a target:
.r:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.mod:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.mod) -o $@ -e $@ $^
# Not a target:
.C:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.S:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.texinfo:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.w.c:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(CTANGLE) $< - $@
# 65 files in 1007 hash buckets.
# average 6.5 files per bucket, max 2 files in one bucket.
# VPATH Search Paths
# No `vpath' search paths

Yorum Gönder

xxxxxx