17 Kasım 2017 Cuma

LINUX KERNEL PROC FILE SYSTEM ÜZERINDE DÖRT İŞLEM

  / Proc dosya sistemi aslında bir sistemdeki işlemler(proccess) hakkında bilgi vermek için geliştirilmiş bir dosya sistemidir. Fakat dosya sisteminin kullanışlılığı göz önüne alındığında, kernel çekirdeğinin birçok elemanı hem bilgiyi rapor etmek hem de dinamik çalışma zamanı yapılandırmasını sağlamak için kullanılıyor.

     / Proc dosya sistemi alt klasörleri  ve sanal dosyalar içerir. Sanal bir dosya kernel çekirdeğiden kullanıcıya bilgi sunabilir ve aynı zamanda kullanıcıdan kernel  çekirdeğe bilgi gönderme aracı olarak da hizmet edebilir. 

     /Proc dosya sistemin üzerinde read,write,open,show,mkdir,symlink vb işlemlerin yapılması mümkündür. Bu yazımızda sadece read ve write methodlarını kullanarak dörtişlem yapabilen bir modül yazacağız.

    Kernel modül aracığı ile kişisel işlemlerimiz için /proc alt dosyaları oluşturabiliriz.Bu yazımızda(Tıklayınız) Kernel Modül programlama hakkında detaylı bilgiye ulabilirsiniz.
    
   Modülümüzde aşağıdaki metholar ile /proc alt dosyalama yapısı oluşturabiliriz.


//Proc oluşturma fonksiyonu
# proc_create("string proc name", permissions, id,&File_Operations)
//Proc silme fonksiyonu 
# remove_proc_entry(ProcName, id);
 
    1: Kernel Modülünün Oluşturulması


# cd /home/omansak/Downloads/linux-4.13.4
# cd ExternalModules
# mkdir ProcCalculator
# cd ProcCalculator
# gedit proc.c
     2: C Modulünün Yazılması
C modulünü yazarken Calculate adın method tanımlayarak bizim için dört işlemi yapacak olan kodları yazacaz. Bu methodu ister /proc alt dosyasının Readmethodunu çalışırken aktif edebiliriz ister Write methodu çalışırken aktif edebiliriz.İki yöntem arasında pek fark yoktur. Sadece user space üzerinde çağrılma farklıkları vardır.


// Kütüpnalerin Tanımlanması
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/proc_fs.h> 
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <linux/init.h>

//Modul Hakkında bilgilerin tanımlanması
MODULE_LICENSE("GPL");
MODULE_AUTHOR("NativeCore");

//Proc Name ve Proc Size tanımlanmaso
#define ProcName   "NativeCore"
#define MaxSize   1024

//Alınacak girdinin max uzunluğunun tanımlanması
#define MaxLenght  10

//Kullanılan Fonksiyonların tanımlanması 
static ssize_t ProcRead(struct file *filp,char *buf,size_t count,loff_t *offp );
static ssize_t ProcWrite(struct file *filp,const char *buf,size_t count,loff_t *offp);
static void Calculate(char* values);
static int Check(char c);

//Proc Struct yapısının tanımlanması ve izin verilen fonksiyonların atanması
static struct proc_dir_entry  *ProcEntry;
static const struct file_operations FileOperations = {
  .owner = THIS_MODULE,
  .read = ProcRead,
  .write = ProcWrite 
};

//Dosya yazma yada okuma esnasında aracı olarak kullanılan buffer tanımlanması
static char ProcBuffer[MaxSize];
static unsigned long BufferSize;

//init(başlangıç) methodunun tanımlanması
static int onStart(void)
{
    //Proc dosyasının oluşturulması
 ProcEntry = proc_create(ProcName, 0, NULL,&FileOperations);
 if (ProcEntry == NULL)
 {
        //Memory yetersizliği yada diğer durumlar için oluşacak hata sonunda proc silinmesi
  remove_proc_entry(ProcName, NULL);
  printk(KERN_ALERT "/proc/%s oluşturulamadı.\n", ProcName);
  return ENOMEM;
 }
    //Proc izinlerinin tanımlanması
 proc_set_user(ProcEntry,KUIDT_INIT(0),KGIDT_INIT(0));
 proc_set_size(ProcEntry,37);
 printk(KERN_ALERT "/proc/%s başarı ile oluşturuldu.\n", ProcName);
 return 0;

}

//exit(kapanış) methodunun tanımlanması
void onExit(void)
{
 remove_proc_entry(ProcName, NULL);
 printk(KERN_ALERT "/proc/%s kaldırıldı\n", ProcName);
}

//Read methodunun tanımlanması
static ssize_t ProcRead(struct file *filp,char *buf,size_t count,loff_t *offp )
{
 printk(KERN_ALERT "ProcRead çalıştırıldı \n");
    //Kernel space'den user space'e verilen aktarılması
 if (copy_to_user(buf, ProcBuffer, BufferSize)) {
  printk(KERN_ALERT "ProcRead : Proc dosyası kopyalanmadı\n");
  return -EFAULT;
 } 
 //Calculate(ProcBuffer);
 return BufferSize;
}

static void Calculate(char* values)
{
    //Dört işlem için kullanılacak değişkenlerin tanımlanması
 static char stringOne[10];
 static char stringTwo[10];
 static long numberOne;
 static long numberTwo;
 static char proccess;
 static int i = 0;
 static int j = 0;

    //+-*/ işaretlerinden birini görene kadar olan tüm karakterleri birinci sayı dizisine aktarılması
 while (Check(values[i]) == 0)
 {
  stringOne[j] = values[i];
  j++;
  i++;
 }

    //+-*/ kulllanılacak işlemin atanaması
 proccess = values[i];
 j = 0;
 i++;

    //+-*/ den sonraki tüm karakterleri ikinci sayı dizisine atanması
 while (i < BufferSize)
 {
  stringTwo[j] = values[i];
  j++;
  i++;
 }

    //Karakter dizilerinin integer dönüştürülmesi
 if (kstrtol(stringOne, 10, &numberOne) != 0)
 {
  printk(KERN_ALERT "1.Sayı : Geçersiz Karakter\n");
  return;
 }
 if (kstrtol(stringTwo, 10, &numberTwo) != 0)
 {
  printk(KERN_ALERT "2.Sayı : Geçersiz Karakter\n");
  return;
 }

    //Yapılacak işleme göre methodun yapılması ve ekrane basılması
 static int result;
 switch (proccess)
 {
 case '+':
  result = numberOne + numberTwo;
  break;
 case '-':
  result = numberOne - numberTwo;
  break;
 case '*':
  result = numberOne * numberTwo;
  break;
 case '/':
  result = numberOne / numberTwo;
  break;
 default:
  printk(KERN_ALERT "Geçersiz Karakter Girildi\n");
  break;
 }
 printk(KERN_ALERT "%d %c %d = %d\n", numberOne, proccess, numberTwo, result);
}

//+-*/ yardımcı karakter ayırt etme methodu
static int Check(char c)
{
 if (c == '+' || c == '-' || c == '*' || c == '/')
  return 1;
 else
  return 0;

}

//Write methodunun tanımlanması
static ssize_t ProcWrite(struct file *filp,const char *buf,size_t count,loff_t *offp)
{

    // Girilen verinin boyutu izin verilen boyutun üstende ise izin verilen boyuta çekilmesi 
 printk(KERN_ALERT "ProcWrite çalıştırıldı\n");
 BufferSize = count;
 if (BufferSize > MaxSize) {
  BufferSize = MaxSize;
 }
 if (copy_from_user(ProcBuffer, buf, BufferSize)) {
  printk(KERN_ALERT "ProcWrite : Proc dosyası kopyalanmadı\n");
  return -EFAULT;
 }
 Calculate(ProcBuffer);
 return BufferSize;
}
module_init(onStart);
module_exit(onExit);

     3: Makefile Yazılması


obj-m = proc.o
all:
 make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
     4: Modülün derlenmesi ve aktif olması
# make
# insmod proc.ko (aktif etme)
# rmmod proc (inaktif etme)

    

     5: Proc dosya sisteminin çağrılması

   Öncellikle proc alt dizinine girilmesi gerekmektedir.

# cd ../proc
   Modülümüzü aktif olmasından sonra /proc klasörünün içerisine verdiğimiz isme göre dosya oluşacaktır (/proc/NativeCore)


 

   Görüldüğü üzere dosyamız oluştu ve artık bu dosyaya veri yazabilir yada okuyabiliriz.     5: Proc dosya veri yazılması ya da okunması

   Modül üzerinde ki Write methodu ile proc dosyasına veri yazmak için "echo"komutu kullanılır.
### Proc Dosyasına veri yazmak için ####
# echo "string veri" > ProcName


# echo "15+65" > NativeCore
# dmesg
  Echo komutu kullandıktan sonra veriler proc dosyamıza yazılmış olacaktır. 

Örnek Toplama İşlemi


Örnek Çarpma İşlemi

Bu örnekte Write Methodundan sonra hesaplama işlemlerini yaptık. Read Methodundan sonra hesaplama işlemlerini yapmak için


#### Proc Dosyasından veri okumak için ####
# cat ProcName
# echo "15+65" > NativeCore
# cat NativeCore

     6: Modulden Çıkılması


#rmmod proc
Olası Hatalar ve Çözümleri

1: "Makefile:3: *** missing separator. Stop".
Makefile dosyanızda boşluk(Space) karakterleri olabilir,bu karakterler yerine TAB karakteri koymalısınız.
2: "make not found"
Bu hata Kernel Kaynak kodlarının bozulması sonucunda meydana gelir, güncel Kerneli indirip tekrar derlenip kurulması gerekir.
3"Bad Adrress" or "Is not proccess"
Bu hata genellikle Write Read methodları içinde veri okurken copy_to_user yada copy_from_user fonksiyonlarının karıştırılması sonucu oluşur 
4:"Could not save file"
Bu hata Kernel Dosyalarını değiştirmek için yönetici izninizin  olmadığını belirtir.

Yönetici şifrenizi oluşturmadıysanız 
# sudo passwd root
Yönetici olarak terminalde işlem yapmak için 
# su
C dosyasının derlerken alınan hatalar için komut satırı incelenmeli ve hataların ayıklanması gerekmektedir. En çok karşılaşan hatalar /proc dosyası için tanımlanan write/readmethodlarının geri dönüş tipi yada parametlerin hatalı olmasından kaynaklamakdatır.

Linux Terminal Komutları
1: "cd" istenilen klasöre girilmesi
2: "ls" klasör içeriğinin görülmesi
3: "mkdir" klasör oluşturulması
4: "gedit" dosya açılması yada düzenlenmesi
5: "su" yönetici olarak girilmesi
6: "dmesg" kernel/debug mesajlarının görülmesi
7: "make" kernele ait komut olup derlenme işlemini yapar
8: "insmod" kernel modülünün aktif olması
9: "rmmod" kernel modülünün inaktif olması
10: "echo" veri yazılması
11: "cat" veri okunması
12: "lsmod" modüllerin listelenmesi


Grup Üyeleri

                   OSMAN ŞAKİR KAPAR (Takım Lideri)

12 Ekim 2017 Perşembe

Linux Kernel Modül Geliştirme













KULLANICIDAN ALINAN İKİ İNTEGER SAYININ MODULER PROGRAMLAMA KULLANILARAK TOPLANMASI 

Öncelikle modüler programlama ile ilgili araştırma yaparak modüler programlamanın ne olduğunu ve neden kullanmam gerektiği hakkında bilgi edindim. Yaptığım araştırmalar sonucu hazırladığım sizler için de faydalı olacağını düşündüğüm özet aşağıda verilmiştir;

Modül Nedir ?

Kernel modülü, kernele sonradan eklenip çıkartılabilen kodlardır. C ile geşliştirilen Kernel Modülleri aslında sıradan bir programdan çok da farklı değildir.

Neden Modül Kullanmalıyız ?

Linux’da donanımlar kernel sürücüleri tarafından kullanılırlar. Bu modüller genellikle lib/modules dizisi altında bulunurlar ve açılış anında yüklenirler. Sistem içerisinde hazır modüller olduğu gibi kendimiz de modül ekleyebiliriz. Kernelin fonksiyonelliğini sistemi yeniden başlatmadan modüller sayesinde arttırılabilir. Bir donanım sürücüsünü düşünecek olursak, sürücü ile kernel, sistem ve donanım arasındaki bağlantıyı sağlayacaktır. Fakat bu işlem için kernele eklenti yapmamız gerekecektir. Kernele yapılacak her hangi bir müdahalede, kernelin tekrar derlenmesi ve sistemin yeniden başlatılması gerekir. Sunucu sistemleri gibi sürekli açık kalması gereken bilgisayarlar için yeniden başlatma işlemi istenmeyen bir durumdur. Bu tip durumları önlemek için modüller kullanılmaktadır.

=>Başlarken C kodları yazmak için kernel içinde  editöre .c uzantılı kısma yazmam ve başka bir editöre Makefile oluşturmam gerekiyor.
Deneme amacı ile  vim editörünü “apt-get install vim” kullanarak indirdim ve “hello World” yazdırabileceğim c kodunu editörde ayrılan kısma yazdım. Aynı şekilde Makefile oluşturmak için vim ile bir editör açtım. Makefile dosyası içerisinde projeyi derlerken işimizi kolaylaştıracak olan tanımlamalar bulunur.  Makefile dosyasını yazdıktan sonra “make” yazarak derlemeye çalıştım ve aşağıdaki hatayı aldım:
“Missing Separator” hatasını düzeltebilmek için uzun bir  araştırma yaptım ve Makefile dosyamda space yerine tab tuşu kullanamam gerektiğini öğrendim ancak daha sonra “No Target” ile devam eden hata aldım ve uzun süre çözemedim. Sorunun kullandığım editörden kaynaklandığını düşündğüm ve gedit kullanmayı denedim.

1. Linux-4.13.3 kernel içinde “open in terminal” dedikten sonra su ile root oldum .

2. mkdir NewModules adlı dosya oluşturdum

3. NewModules içinde “gedit Sum.c” komutunu yazarak açılan editöre c kodlarımı yazdım ve kaydettim. Sum.c ‘inin içeriği;



4. yine aynı dosya içerisinde “gedit Makefile” yazarak Makefile dosyasını tab kullanmaya dikkat ederek yazdım. Makefile içeriği;



5. “make” yazarak derlemeye çalıştım ve hata aldım aynı işlemleri başka dosyalar açarak tekrarladım her seferinde aldığım hata;




Hatanın kullandığım editörden bağımsız olduğunu anladım ve başka bir terminalde kernelimde herhangi bir yerde “make” veya “defconfig” “make menuconfig” yazdığımda “no targets” ve “no.. file” şeklinde hata aldım. Yaptığım işlem ve araştırma yaparak uyguladıklarım kernelde uzantılarda bir değişiklik yapmış veya yanlışlıkla gerekli dosyalarını lib/ altında silmiş olduğumu düşündüğüm için önceden indirdiğim “linux-4.13.3.tar.xz” dosyasını kullanarak ;
#make deconfig
#make
#make_modules
#make modules_install
#make install
#reboot
Adımlarını en baştan yaparak kurdum ve eskisini sildim.
ð Yeni kernel üzerinde NewModules dosyasını yukarıda anlattığım gibi yazdım , “Sum.c” ve Makefile yeniden oluşturdum.

ð  Bundan sonra “make” yazarak derlenmesini bekledim.


Derlendikten sonra oluşan dosyalar ;

6. “insmod Sum.ko numberOne=10 numberTwo=12” satırını yazdıyoruz.
İnsmod modulu kernele eklemek için kullanılır.
7.dmesg diyerek görmek istediğimiz toplamı elde ediyoruz.







8. rmmod –f Sum ile modülü kapatabilir silebiliriz


29 Eylül 2017 Cuma

Linux Kernel

Ödev 1 :
Konu :  Linux kurulumu ve Kernel.org sitesinden son güncel kernel in indirilmesi ve opensource olarak kurulması
Öncelikle daha önce hiç Linux bilgim olmadığı ve sanal makine kullanmadığım için araştırma yaptım.
Elde ettiğim sonuçlar özet olarak;
Linux çekirdeği, Ubuntu, CentOS ve Fedora dahil olmak üzere tüm Linux işletim sistemlerinin hayat gücüdür diyebiliriz.
Çoğu, OS'yi kurduğunuzda varsayılan olarak yüklendiğinden, çekirdeği derlemek zorunda kalmayız. Ayrıca, çekirdek için kritik bir güncelleme yapıldığında, Linux sisteminizdeki çekirdeği güncellemek için yum veya apt-get kullanabiliriz.
Bununla birlikte, çekirdeği kaynaktan derlemeniz gerekebilecek belirli durumlarla karşılaşabiliriz. Aşağıdakiler Çekirdek'i Linux sisteminizde derlemek zorunda kalabileceğimiz birkaç durumdur.
Varsayılan çekirdeğin parçası olmayan deneysel özellikleri etkinleştirmek.
Şu anda varsayılan çekirdek tarafından desteklenmeyen yeni bir donanım desteğini etkinleştirmek.
Çekirdeği hata ayıklamak için
Veya sadece çekirdeğin nasıl çalıştığını öğrenmek için çekirdek kaynak kodunu keşfetmek ve kendi derlememizi isteyebiliriz.
Bu ödev raporunda, kaynaktan Linux çekirdeği nasıl derlemeye çalıştığımı anlatacağım.
=>Ubuntu kulanmaya karar verdim ve birkaç denemeden sonra bilgisayarımın sanal makine uyumunu enable yaparak kurmayı başardım. Kurulum ve internete bağlanmak için gerekli yüklemeleri yaptım.
1. İlk adım kernel.org'dan en son kararlı çekirdeği indirmek
Terminaldeki işlemlerim;
#cd /usr/src/


Daha sonra 4.13.3 tarbar  indirdim.(projeyi yaptığımda güncel olan 4.13.3 idi.)




2. İkinci adım derleme için çekirdek kaynak tar dosyasını açmak;
# tar -xvJf linux-4.13.3.tar.xz
3. Çekirdeği Yapılandırma
# make menuconfig ‘de “sudo apt-get install libncurses” indirmeye çalışsam da  hata aldığım için make defconfig yaparak yapılandırma yaptım.Bu işlemden önce ve sonraki durumlar;







4. Linux çekirdeğini derlenmesi
Ana çekirdeği derleme:
# make

Çekirdek modüllerini derleme:
# make modules

Çekirdek modüllerini yükleme:
# make modules_install

5. Yeni Çekirdeği Kurulması

Yeni çekirdeği sisteme yüklenmesi:
# make install
6. Linux'u yeni çekirdeğe boot edilmesi

Yeni derlemiş olduğunuz yeni çekirdeği kullanmak için sistemi yeniden başlattım.

# reboot


ð Sistem tamamlandıktan sonra, Linux çekirdeğinin yeni sürümünün yüklü olduğunu doğrulamak için uname komutunu kullandım.
ð