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.