16 Haziran 2007

capture key

Linux'te hiç herhangi bir tuşa basılınca haberim olsun gibi bir ihtiyacınız oldu mu bilemiyorum ama benim oldu. Mesela bana şu yüzden gerekti:
Bende quake3'ten çıkarken kilitleniyor ve ekran değişmiyor hiç bir şekilde. Hemen başka bir bilgisayar bulup ssh bağlantısı yapıp quake'i öldürürsem düzeliyor sadece. Yoksa reset atmak zorundayım.
Ben de bir çözüm buldum hemen: özel bir tuşa basınca quake sonlandırılsın.

/dev/input/event0

açıp input_event structure ına koyuyoruz ve hangi tuşa basılmış anlıyoruz.

struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};

Beni reset atmaktan kurtarıp quake i öldürmeye yarayan kod (root ile çalıştırın):

#include <linux/input.h>
#include <fcntl.h>
#include <stdio.h>

int main()
{
int fd;
struct input_event inp;
fd = open("/dev/input/event0", O_RDONLY);
while (1)
{
read(fd, &inp, sizeof(inp));
//printf("code: %d\n", inp.code);
if (inp.code == 98)
system("killall quake3-smp.x86");
}
close(fd);
return 0;
}

Burada 98 benim klavyede bulunan garip bir tuşa setkeycodes ile atadığım değer. Siz inp.code u ekrana basarak istediğiniz tuş hangisiymiş görebilirsiniz. Benim kod, belirlediğim tuşa basıldığında killall quake3-smp.x86 komutunu çalıştırıyor.

02 Mayıs 2007

process'ten process'e signal (sinyaller) öğrenmek

Merhaba, geçenlerde bilgisayarımda çalışıyordum ve aklıma sinyaller ile ilgili şeyler geldi. Mesela hangi process hangi process'e ne sinyali göndermiş, kim kime SIGKILL yapmış kim SIGHUP (ve bir sürü sinyal..) yapmış görmek istedim ve çekirdekte küçük bir değişiklikle bu özelliği elde ettim.
Sonuçta dmesg çıktısında hangi process hangi process'e ne göndermiş görebileceğiz.
Öncelikle sinyal nedir nasıl gönderilir bilmeyenler için onu belirteyim. kill sistem çağrısıyla gönderilir. Sinyali alan process handle ediyorsa eder (event-driven programlama gibi).
Not: Bazı sinyaller handle edilemez, SIGKILL (meşhur 9. sinyal) gibi.
Kısa bir sinyal anlatımından sonra konumuza dönelim. Şimdi bu kill fonksiyonunun çekirdekteki karşılığı olan sys_kill fonksiyonuna biraz ekleme yapalım ki her kill çağrılışında bizim eklediklerimiz de yapılsın.
Çekirdek kaynak kodumuzdaki kernel/signal.c dosyasını açıyoruz ve sys_kill fonksiyonunu buluyoruz.

struct task_struct *task;

task = find_task_by_pid(pid);
if (task)
printk(KERN_DEBUG "SIGNAL: %d from pid: %d (%s) to pid: %d (%s)\n", sig, current->pid, current->comm, pid, task->comm);
else
printk(KERN_DEBUG "SIGNAL: %d from pid: %d (%s) to pid: %d\n", sig, current->pid, current->comm, pid);

bu kodu ekliyoruz.
Bu kadar karışık olsun istemiyorsanız sadece else'ten sonra gelen tek satır da yeter. Üstte kalan kısım sadece sinyalin gittiği process'in adını alabilmek için.
Bunu yaptıktan sonra kernel outputu çok sık sinyallerle dolacaktır (rahatsız edici bir durum). Çünkü sinyaller çok fazla kullanılıyor.
Mesela en basitinden bir terminalde iken CTRL+C ye basın. Prompt bir satır aşağıya kayacaktır. dmesg yaptığımızda kabuğumuzun pid'inden kendine 2 nolu sinyal geldiğini göreceğiz.

SIGNAL: 2 from pid: 6029 (bash) to pid: 6029 (bash)

bendeki çıktı böyle oldu. Kendisine SIGINT (2 nolu sinyal) gelmiş bulunuyor. Hangi numaralı sinyalin hangi sinyal olduğuna signal.c dosyasının üstündeki tablodan bakabilirsiniz.

Bu arada bunun daha gelişmişi ya da daha düzenlisi diyeyim için şunlar yapılabilir:
printk ile değil de proc üzerinden ya da sysfs üzerinden haberleşen bir yapı çok güzel olurdu (kernel space'ten, user space'e proc ile haberleşmek). Bir de user space daemon yazmak lazım log tutan. Böylece kernel output'unu da kirletmemiş oluruz.

İyi çekirdek hacklemeler :)

08 Nisan 2007

saat sorunu

Bilgisayarın saatini localtime olarak kullanıyorum. Yani /etc/default/rcS deki utc=no. Ancak sistem her açıldığında saat birkaç saat farklı oluyor. hwclock çıktısını almayı denediğimde /dev/rtc sorunuyla karşılaştım.
$ hwclock --show --localtime
select() to /dev/rtc to wait for clock tick timed out

hwclock'a --directisa parametresini vererek görebiliyorum. Bu yüzden saatin ayarlandığı açılış scriptinde parametreler kısmına bunu ekledim ve düzeldi. Artık bios ile aynı saatim, mutluyum :)
Bunu yapmak için /etc/init.d/hwclock.sh dosyasındaki HWCLOCKPARS değerini ayarlayın aşağıdaki gibi:
HWCLOCKPARS=--directisa
Bu ayarları yaparken benim sistemin debian olduğunu unutmayın :)

16 Mart 2007

parity bits ve hamming code

Biraz zaman buldum ve hamming code anlatayım diye düşündüm.

Ne işe yarar?
Veri transfer ederken küçük hatalar oluşur ve bunların tespiti ve düzeltilmesi, gerekirse yeniden yollanması gerekir. Benim anlatacağım yöntemde 1 bit hatalı ise tespit edilip düzeltiliyor.

Nedir?
Göndereceğimiz dataword 8 bit olacak ve ek olarak 4 parity bitimiz ile toplam 12 bitlik dataword gönderiyoruz. Yani aslında göndermek istediğimiz data 8 bit, geri kalan 4 bit sadece tespit ve düzeltebilme amaçlı.

Anlatmaya hemen örnek ile başlamak en iyisi.

Göndermek istediğimiz dataword 11001010 olsun. Bu datawordu yeni hesaplayacağımız parity bitler ile birlikte yazacağız. Parity bitleri 2 nin kuvvetleri olan pozisyonlara gelecek.
xx1x100x1010
2 nin kuvvetleri olan pozisyonlara şimdilik x koyduk (yani 1, 2, 4, 8 inci pozisyonlara). Bu pozisyonlara parity bitleri hesaplayıp yazacağız şimdi.

Birinci pozisyon için 3, 5, 7, 9, 11 deki sayılara bakıp even parity ye göre yazıyoruz.
Yani (1+1+0+1+1) % 2 = 0. Yani dataworddeki ilk bit 0 olacak. Aynı şekilde diğerlerini de hesaplayalım:
İkinci pozisyon için 3, 6, 7, 10 11.
Yani (1+0+0+0+1) % 2 = 0.
Dördüncü pozisyon için 5, 6, 7, 12.
Yani (1+0+0+0) % 2 = 1.
Sekizinci için 9, 10, 11, 12.
Yani (1+0+1+0) % 2 = 0.

Bu dört parity bitimizi de hesapladıktan sonra datawordümüzün son durumu
001110001010
Evet bunu anladık ama o pozisyonlar nereden geldi dediğinizi duyabiliyorum :) Onları şimdi anlatıp yazının akışını bozmak istemiyorum ama buna yorum olarak anlatacağım.

Son hesapladığımız 12 bit uzunluğundaki datawordümüzü göndereceğiz ve alıcı taraf dataya bakıp (8 bitlik) yeniden parity bitlerini hesaplayacak ve farklılığa göre anlayacak.
Bu giden datawordün mesela 3. bitinin yanlış olarak gittiğini (1 değil de 0 olarak) varsayalım. Alıcı tarafın elindeki dataword şöyle
000110001010
Şimdi alıcı taraf tekrar parityleri hesaplayacak.
xx0x100x1010
Yine aynı şekilde o pozisyonlara bakıp birinci, ikinci, dördüncü ve sekizinci pozisyondaki bitleri hesaplıyoruz yani parity bitlerini.
(0+1+0+1+1) % 2 = 1
(0+0+0+0+1) % 2 = 1
(1+0+0+0) % 2 = 1
(1+0+1+0) % 2 = 0
Şimdi hesapladığımız parity bitler 1110 yaptı. Oysa bize gelen datawordde 0010 idi. Şimdi bu iki parityde bitleri karşılaştırıp, farklı olanlar için 1, aynı olanlar için 0 yazacağımız yeni bir sayı yaratacağız. Yani XOR layacağız.
1110
0010
____(xor)
1100
Ürettiğimiz sayı 1100. Bunu tersten yazıyoruz yani 0011.
0011 ikilik sistemde bir sayı, bunu onluk sisteme çevirirsek 3 olur. Bu da bize 12 bitlik datawordümüzde kaçıncı bitin hatalı gelmiş olduğunu gösterir. Hatırlıyorsanız yukarda 3. biti bozmuştuk zaten. Hatayı tespit ettik, düzeltmek içinse tek yapmamız gereken 3. biti değiştirmek.

Bize üçüncü sınıfta verilen "Data Communications" dersinin bir ödevi de bunun kodunu yazmaktı C ile. Kodu buradan indirebilirsiniz. Dosyadan 12 bitlik datawordler okuyup, hatalıysa düzeltip ekrana basıyor.

04 Mart 2007

sockettraffic

Geçen hafta yapmaya başladığım sockettraffic ile hiç ilgilenemedim bu hafta dolu geçti. Bugün zaman buldum ve 3 saatlik bir kodlama sonunda artık hangi bağlantı kaç kb/s ile veri çekiyor ve bağlantıyı hangi process yapmış görebiliyoruz. Umarım yakında tam fonksiyonel olup, tcp6 ve udp bağlantıları da gösterir.

24 Şubat 2007

linux sockettraffic

Linuxte çok fazla seçeneğimiz var (ntop, iptstate, iptraf...) network trafiğini görebilmek için. Bu programlar gerçekten de detaylı bilgiler veriyor. Fakat linux dünyasında henüz processlerin saniyedeki veri hızını gösteren basit bir tool bulamadım. Windows kullandığım günlerde bu tür araçlar kullanırdım hep.
Ben de kendim yazmaya karar verdim ve dün gece başladım. C ile yazdığım programın adı sockettraffic olacak. Bu yazıyı yazarken aynı zamanda programı da yazıyorum. Şuan processlerin socket bilgilerini almak bitti, herhalde bugün de linked listlerle uğraşırım processlerin bilgilerini tutmak için. Şuan için öyle gözüküyor ki, programı non-root olarak çalıştırınca sadece hangi porttan hangi adrese ve porta bağlıyız onu gösterecek. Program root olarak çalıştırıldığında ise bu bağlantıları hangi processlerin yaptığı ve hızları KB/s cinsinden yazacak.
Kullanıcı arayüzüne gelecek olursak, sadece konsolda çalışan bir uygulama olacak, sanırım ncurses a ihtiyacım olacak. Belki ileride graphical bir araç da olur hatta applet belki de :)

12 Şubat 2007

freebsd quake3 ses

Linuxte ses sitemi olarak alsa kullanan uygulamaların sesleri mixlenerek çıkabiliyor. Ama oss kullanan, /dev/dsp yi kullanan uygulamalarda sadece tek ses çalabiliyor sistem. Mesela hem quake 3 oynayıp hem de amaroktan müzik dinleyemedim hiç bir zaman :-)
FreeBSD oss yi kullanıyor ama bunu yapabiliyor. sysctl ile ayarlanabilen hw.snd.pcm0.vchans değeri kaç olursa o kadar kanal aynı anda çalınabiliyor.

# sysctl hw.snd.pcm0.vchans=4
# sysctl hw.snd.maxautovchans=4

ile şuanki ve yeni yüklenecek modüller için kanal sayısını 4 olarak ayarladık. Bu sayede amarokta şarkı çalarken sesli quake 3 de oynayabiliyorum (linuxte hiç yapamamıştım:-))
Bu arada oynadığım quake 3, linux binary si (zaten quake3 ün native FreeBSD sürümü yok) ve harika çalışıyor. FreeBSD nin linux binary compatibility si gerçekten harika, hatta bazı uygulamaların linuxte olduğundan da iyi çalıştığı belirtiliyor.

08 Şubat 2007

loopback image disk yapmak

Bugün initrd olarak da kullanabileceğiniz disk imajı yapmayı anlatmaya karar verdim. Gerçi yeni kerneller cpio arşivi kullanıyorlar ama bu da olur :)

Öncelikle boş bir dosya yaratarak başlayalım, adı im olsun (mesela 8 MB olsun):
$ dd if=/dev/zero of=im bs=1M count=8
8+0 records in
8+0 records out
8388608 bytes (8.4 MB) copied, 0.0377943 seconds, 222 MB/s

Dosya yaratmak yerine /dev/ram0'da da yapabilirsiniz bu işlemi.

Şimdi dosyamızda file system yaratmaya sıra geldi, ext2 oluşturalım.
$ mkfs.ext2 im
mke2fs 1.40-WIP (14-Nov-2006)
im is not a block special device.
Proceed anyway? (y,n) y
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
2048 inodes, 8192 blocks
409 blocks (4.99%) reserved for the super user
First data block=1
Maximum filesystem blocks=8388608
1 block group
8192 blocks per group, 8192 fragments per group
2048 inodes per group

Writing inode tables: done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 25 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.

Eveeet dosya sistemimizi de oluşturduktan sonra dosyamızı mount edip (loopback olarak) içine istediğimizi koyup umount edebiliriz. Artık o bir disk imajı. Gzip'leyip initrd olarak da kullanabiliriz.
# mount -o loop im /mnt/x
$ mount
/home/alp/im on /mnt/x type ext2 (rw,loop=/dev/loop/0)

01 Şubat 2007

sharehttp

Bilgisayarlar arasında dosya transferi her zaman gerekiyor. Evimizde özellikle ağdan devamlı dosya transferi ihtiyacı duyarız. Her şeyi ayarlanmış bilgisayarlarımız varsa dosyaları kolayca paylaşırız ama devamlı yeni sistem kuruyorsak paylaşmak gıcık bir işlemdir (samba, nfs, ftp hiçbiri yokken ve kurmak istemiyorsak).
Ağdaki başka bir bilgisayardan dosya almak için http iyi bir seçim, çünkü her bilgisayarda browser ya da wget gibi araçlar var.

Dosya sunan http server ruby ile birkaç satırda yapılabiliyor. Aşağıdaki kodu sharehttp ismiyle kaydedip çalıştırma izni verdikten sonra normal bir program gibi (sisteminizde ruby yüklüyse) kullanabilirsiniz.

#!/usr/bin/ruby
#Alp OZKUL, Feb 2007

if ARGV.length == 0
port = 4000
path = Dir::pwd
elsif ARGV.length == 1
if ARGV[0] == "-h" || ARGV[0] == "--help" || ARGV[0] == "-help"
puts " Usage: sharehttp [PATH] [PORT]"
puts " Default values are PORT=4000, PATH=current working directory"
exit
end
port = 4000
path = ARGV[0]
elsif ARGV.length == 2
port = ARGV[1].to_i
path = ARGV[0]
else
exit
end

puts "(CTRL+C to exit)"
puts "PATH: #{path}"
puts "PORT: #{port}"

require 'webrick'
include WEBrick

server = HTTPServer.new(
:Port => port,
:DocumentRoot => path
)

trap("INT"){ server.shutdown }
server.start
Kullanmak için /usr/bin/sharehttp olarak kaydedip, çalıştırma izni verebilirsiniz(ya da PATH inizde istediğiniz bir yere). Mesela /home/alp dizinini paylaşmak istiyorum:
sharehttp /home/alp
Browserdan http://localhost:4000 e girip dizinin listelenmiş olduğunu göreceksiniz.

19 Ocak 2007

dosya izinlerindeki s biti

Bazı dosyalarda çalıştırılabilir biti (x) yerine s görebilirsiniz. Bu demek oluyor ki program çalıştırıldığında, çalıştıran değil de dosyanın sahibi effective user olsun. Ama hala real user programı çalıştırandır. Bunu da setuid ailesi fonksiyonlarla değiştirebiliriz.

Neyse bunların nerede lazım olduğuna bakacak olursak, her yerde lazımlar :) Mesela passwd komutuyla şifremizi değiştiriyoruz. Nasıl oluyor da bizim çalıştırdığımız bir program /etc/shadow dosyasını değiştiriyor yetkimiz olmadan. Çünkü bu uygulamalar s biti kullanılan setuid uygulamalarıdır.

alp@AR-deb:~$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 28480 2006-12-07 18:28 /usr/bin/passwd

Gördüğünüz gibi dosyanın sahibi root ve s biti ayarlanmış. Yani çalışınca effective user root olacak.

18 Ocak 2007

grub freebsd

Grub ı hepimiz biliriz mükemmel bir boot loader dır kendisi. Herşeyi açar, tanıdığı sistemleri kendi açar, tanımadıklarını chainloader yöntemi ile açılacak sistemin boot loader ını açar. Ayrıca grub menüden istediğimiz OS u seçerken e tuşuna basıp o satırları düzenleyip, b tuşuna basarak düzenlediğimiz özellikler ile boot ettirme yetisine de sahiptir. Ya da c ye basıp tamamen komut yazıp en son boot komutu verip açmamıza da izin verir.

Ancak garip bi durum var ki (hata mıdır bilmiyorum) FreeBSD yi boot edecek iken c ye basıp gerekli şeyleri yazıp boot ettiğimizde acpi.ko yükleniyor derken kilitlenip kalıyor. Ama bunun yerine zaten ayarlanmış ise(menu.lst den) menüden seçerek boot ettiğimizde sağlam açılıyor. Ya da e ye basıp bi kaç satır düzenleyip b ile boot edersek yine açılıyor. İlginç bi durum.

Not: Bunu denediğimde grub 0.97 (en güncel) kullanıyordum.

08 Ocak 2007

Rights

Bu bir php web uygulaması. Geçtiğimiz yaz blog, wiki, sözlük karışımı ve dosya sistemi özellikleri gösteren bir web uygulaması yapmayı denemenin ilginç olacağını düşünerek yapmıştım.

Version: 1.2

Özellikler:
  • Site yöneticileri, yeni üye almayı kısıtlayabiliyor ve her hakka sahip.
  • Dosya upload etme(hakkınız varsa).
  • Gruplar.
  • Yazdığınız yazı için belirli kullanıcılara veya gruplara göre istediğiniz hakları verebilirsiniz.
  • Haklar: okuma, değiştirme, silme, arama.
  • Üye olmayanlar da ayrı bir kullanıcı olarak geçtiği için onlara da bu hakları verebilirsiniz.
Açık kaynak kodlu bu uygulamayı buradan indirebilirsiniz.

07 Ocak 2007

rlimit ve sigxcpu

ulimit yapar gibi processin resource larını kısıtlayabilirsiniz. Bunun için getrlimit, setrlimit fonksiyonları ve rlimit structure ı vardır:
struct rlimit {
rlim_t rlim_cur; /* Soft limit */
rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */
};
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);

Görüldüğü gibi, structure iki tane değer içeriyor. Bunlardan current limit olan, soft limit olarak da adlandırılır, diğeri maximum limit ise hard limit olarak adlandırılır. Current limitimizi, maximum limiti geçmeyecek şekilde ayarlarız.

Örnek olarak RLIMIT_CPU resource unu limitleyip etkisini görelim:

#include <sys/resource.h>
#include <sys/time.h>

int main ()
{
struct rlimit rl;
getrlimit(RLIMIT_CPU, &rl);
rl.rlim_cur = 1;
setrlimit(RLIMIT_CPU, &rl);

while (1);

return 0;
}

Şimdi derleyip çalıştıralım:
$ gcc limit-cpu.c -o limit-cpu
$ ./limit-cpu
CPU time limit exceeded
1 saniye olarak ayarladığımız cpu-time ı aşan process imiz SIGXCPU sinyali aldı ve öldürüldü.
Bu sinyal handle edilebiliyor. Handle edip process imizi devam ettirirsek her saniyede bir bu sinyal alınmaya devam edilir ve hard limite ulaşıldığında SIGKILL sinyali alınır. Ama bu durum değişen bir davranıştır linux un kendi farklı çekirdek versiyonlarında bile. Uygulamamızın portable olması için SIGXCPU aldığımızda process ölmeli.

03 Ocak 2007

FreeBSD ve gnome 2.16.2


FreeBSD sistemimde dunden beri gnome derleniyor :) Neyse ki bitti ve buradan yaziyorum bu yaziyi.