initrd Tasarımı¶
Sistem İçin Gerekli Olan Dosyalar Ve Açılış Süreci¶
Linux sisteminin açılabilmesi için aşağıdaki 3 dosya yeterli.
distro/iso/boot/initrd.img distro/iso/boot/vmlinuz distro/iso/boot/grub/grub.cfg
Bu dosyaları yukarıdaki gibi dizin konumlarına koyduktan sonra, grub-mkrescue iso/ -o distro.iso #iso doyamız oluşturulur. komutuyla distro.iso dosyası elde ederiz. Artık iso dosyamız boot edebilen hazırlanmış bir dosyadır. Burada bazı sorulara cevap vermemiz gerekmektedir.
distro/iso/boot/initrd.img dosyasını sistemin açılış sürecinden ön işlemleri yapmak ve gerçek sisteme geçiş sürecini yöneten bir dosyadır. Yazın devamında nasıl hazırlanacağı anlatılacaktır.
distro/iso/boot/vmlinuz dosyamız kernelimiz oluyor. Ben kullandığım debian sisteminin mevcut kernelini kullandım. İstenirse kernel derlenebilir.
distro/iso/boot/grub/grub.cfg dosyamız ise initrd.img ve vmlinuz dosyalarının grub yazılımının nereden bulacağını gösteren yapılandırma dosyasıdır.
Bir linux siisteminin açılış süreci şu şekilde olmaktadır.
1- Bilgisayara Güç Verilmesi
2- Bios İşlemleri Yapılıyor(POST)
3- LILO/GRUB Yazılımı Yükleniyor(grub.cfg dosyası okunuyor ve vmlinuz ve initrd.img devreye giriyor)
4- vmlinuz initrd.img sistemini belleğe yüklüyor
5- vmlinuz initrd.img sistemini belleğe yüklüyor
6- initrd.img içindeki init dosyasındaki işlem sürecine göre sistem işlemlere devam ediyor
7- initrd.img içindeki init dosyası temel işlemleri ve modülleri yükledikten sonra disk üzerindeki sisteme(/sbin/init) exec switch_root komutuyla süreci devrederek görevini tamamlamış olur
Yazının devamında sistem için gerekli olan 3 temel dosyanın hazırlanması ve iso yapılma süreci anlatılacaktır.
initrd Nedir? Nasıl Hazırlanır?¶
initrd (initial RAM disk), Linux işletim sistemlerinde kullanılan bir geçici dosya sistemidir. Bu dosya sistemi, işletim sistemi açılırken kullanılan bir köprü görevi görür ve gerçek kök dosya sistemine geçiş yapmadan önce gerekli olan modülleri ve dosyaları içerir.Ayrıca, sistem başlatıldığında kök dosya sistemine erişim sağlamadan önce gerekli olan dosyaları yüklemek için de kullanılabilir.
Gerekli olacak dosyalarımızın dizin yapısı ve konumu aşağıdaki gibi olmalıdır. Anlatım buna göre yapalacaktır. Örneğin S1 ifadesi satır 1 anlamında anlatımı kolaylaştımak için yazılmıştır. Aşağıdaki yapıyı oluşturmak için yapılması gerekenleri adım adım anlatılacaktır.
S1- distro/initrd/bin/busybox #dosya S2- distro/initrd/bin/kmod #dosya S3- distro/initrd/bin/debmod #dosya S4- distro/initrd/bin/insmod #dosya S5- distro/initrd/bin/lsmod #dosya S6- distro/initrd/bin/modprobe #dosya S7- distro/initrd/bin/rmmod #dosya S8- distro/initrd/bin/modinfo #dosya S9- distro/initrd/lib/modules/$(uname -r)/moduller #dizin S10- distro/initrd/bin/systemd-udevd #dosya S11- distro/initrd/bin/udevadm #dosya S12- distro/etc/udev/rules.d #dizin S13- distro/lib/udev/rules.d #dizin S14- distro/initrd/bin/init #dosya S15- distro/iso/initrd.img #dosya S16- distro/iso/vmlinuz #dosya S17- distro/iso/grub/grub.cfg #dosya
Dizin Yapısının oluşturulması¶
- Aşağıdaki komutları çalıştırdığımızda dizin yapımız oluşacaktır.
mkdir -p initrd mkdir -p initrd/bin/ mkdir -p initrd/lib/ ln -s lib initrd/lib64 mkdir -p initrd/lib/modules/ mkdir -p initrd/lib/modules/$(uname -r) mkdir -p initrd/lib/modules/$(uname -r)/moduller mkdir -p initrd/etc/udev/ mkdir -p initrd/lib/udev/ mkdir -p iso mkdir -p iso/boot mkdir -p iso/boot/grub
S1- distro/initrd/bin/busybox¶
busybox hakkında bilgi almak için busybox yazısında anlatılmıştır. Burada sisteme nasıl ekleneceği anlatılacaktır. busybıx dosyamızın bağımlılıklarının lddscript.sh scripti ile initrd içine kopyalayacağız. Yazının devamında Bağımlılık Tespiti konu başlığı altında anlatılmıştır.
cp /usr/bin/busybox initrd/bin/busybox #sistemden busybox kopyalandı.. lddscript.sh initrd/bin/busybox initrd/ #sistemden busybox bağımlılıkları initrd dizinimize kopyalar.
S2-S8 distro/initrd/bin/kmod¶
kmod yazısında kmod anlatılmıştır. Burada sisteme nasıl ekleneceği anlatılacaktır.
cp /usr/bin/kmod initrd/bin/kmod #sistemden kmod kopyalandı.. lddscript.sh initrd/bin/kmod initrd/ #sistemden kmod kütüphaneleri kopyalandı.. ln -s kmod initrd/bin/depmod #kmod sembolik link yapılarak depmod hazırlandı. ln -s kmod initrd/bin/insmod #kmod sembolik link yapılarak insmod hazırlandı. ln -s kmod initrd/bin/lsmod #kmod sembolik link yapılarak lsmod hazırlandı. ln -s kmod initrd/bin/modinfo #kmod sembolik link yapılarak modinfo hazırlandı. ln -s kmod initrd/bin/modprobe #kmod sembolik link yapılarak modprobe hazırlandı. ln -s kmod initrd/bin/rmmod #kmod sembolik link yapılarak rmmode hazırlandı.
S9- distro/initrd/lib/modules/$(uname -r)/moduller¶
Bu bölümde modüller hazırlanacak. Burada dikkat etmemiz gereken önemli bir nokta kullandığımız kernel versiyonu neyse initrd/lib/modules/modules altında oluşacak dizinimiz aynı olmalıdır. Bundan dolayı initrd/lib/modules/$(uname -r) şeklinde dizin oluşturulmuştur. Aşağıda kullandığımız 2. satırdaki /sbin/depmod --all --basedir=initrd, initrd/lib/modules/$(uname -r)/moduller altındaki modullerimizin indeksinin oluşturuyor.
#döngüyle istediğimiz moduller initrd sistemimize dahil ediliyor. for directory in {crypto,fs,lib} \ drivers/{block,ata,md,firewire} \ drivers/{scsi,message,pcmcia,virtio} \ drivers/usb/{host,storage}; do #echo ${directory} find /lib/modules/$(uname -r)/kernel/${directory}/ -type f \ -exec install {} initrd/lib/modules/$(uname -r)/moduller \; done /sbin/depmod --all --basedir=initrd #modüllerin indeks dosyası oluşturuluyor
S9- distro/initrd/bin/systemd-udevd¶
udev, Linux çekirdeği tarafından sağlanan bir altyapıdır ve donanım aygıtlarının dinamik olarak algılanmasını ve yönetilmesini sağlar. systemd-udevd ise udev'in bir bileşenidir ve donanım olaylarını işlemek için kullanılır. Daha detaylı bilgi için udev yazısında anlatılmıştır. systemd için /lib/systemd/systemd-udevd, no systemd için /sbin/udevd kullanılır. Biz systemd için tasarladığımız için /lib/systemd/systemd-udevd kullanıyoruz.
cp /lib/systemd/systemd-udevd initrd/bin/systemd-udevd #sistemden kopyalandı.. lddscript initrd/bin/systemd-udevd initrd/ #sistemden kütüphaneler kopyalandı..
S10- distro/initrd/bin/udevadm¶
udevadm, Linux işletim sistemlerinde kullanılan bir araçtır. Bu araç, udev (Linux çekirdeği tarafından sağlanan bir hizmet) ile etkileşim kurmamızı sağlar. udevadm, sistemdeki aygıtların yönetimini kolaylaştırmak için kullanılır.
udevadm komutu, birçok farklı parametreyle kullanılabilir. İşte bazı yaygın kullanımları:
udevadm info: Bu komut, belirli bir aygıt hakkında ayrıntılı bilgi sağlar. Örneğin, udevadm info -a -n /dev/sda komutunu kullanarak /dev/sda aygıtıyla ilgili ayrıntıları alabilirsiniz.
udevadm monitor:* Bu komut, sistemdeki aygıtlarla ilgili olayları izlemek için kullanılır. Örneğin, udevadm monitor --property komutunu kullanarak aygıtların bağlanma ve çıkarma olaylarını izleyebilirsiniz.
udevadm trigger:* Bu komut, udev kurallarını yeniden değerlendirmek ve aygıtları yeniden tanımak için kullanılır. Örneğin, udevadm trigger --subsystem-match=block komutunu kullanarak blok aygıtlarını yeniden tanımlayabilirsiniz.
udevadm control: Bu komut, udev hizmetini kontrol etmek için kullanılır. Örneğin, udevadm control --reload komutunu kullanarak udev kurallarını yeniden yükleyebilirsiniz.
Bu sadece bazı temel kullanımlardır ve udevadm'nin daha fazla özelliği vardır. Daha fazla bilgi için, man udevadm komutunu kullanarak udevadm'nin man sayfasını inceleyebilirsiniz. Not: udevadm systemd ve no systemd için aynı kullanımdadır. İki sistem içinde geçerlidir.
cp /bin/udevadm initrd/bin/udevadm #sistemden udevadm kopyalandı.. lddscript initrd/bin/udevadm initrd/ #sistemden kütüphaneler kopyalandı..
S12- distro/etc/udev/rules.d--S13- distro/lib/udev/rules.d¶
"rules" kelimesi, Linux işletim sistemi veya bir programda belirli bir davranışı tanımlayan ve yönlendiren kuralları ifade eder. Bu kurallar, sistem veya programın nasıl çalışacağını belirlemek için kullanılır ve genellikle yapılandırma dosyalarında veya betiklerde tanımlanır.
Linux'ta "rules" terimi, genellikle udev kuralları veya iptables kuralları gibi belirli bileşenlerle ilişkilendirilir.
udev kuralları, Linux çekirdeği tarafından sağlanan bir altyapıdır ve donanım aygıtlarının nasıl tanınacağını ve nasıl işleneceğini belirlemek için kullanılır. Örneğin, bir USB cihazı takıldığında, udev kuralları bu cihazın nasıl adlandırılacağını ve hangi sürücünün kullanılacağını belirleyebilir.
Örnek bir udev kuralı:
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", RUN+="/path/to/script.sh"
Bu kural, bir USB cihazı eklendiğinde çalışacak bir betik belirtir. Kural, cihazın üretici kimliği (idVendor) ve ürün kimliği (idProduct) gibi özelliklerini kontrol eder ve belirli bir eylem gerçekleştirir.
Aşağıda sisteme ait kurralar initrd sistemimize kopyalanmaktadır.
cp /etc/udev/rules.d -rf initrd/etc/udev/ cp /lib/udev/rules.d -rf initrd/lib/udev/
S14- distro/initrd/bin/init¶
kernel ilk olarak initrd.img dosyasını ram'e yükleyecek ve ardından init dosyasının arayacaktır. Bu dosya bir script dosyası veya binary bir dosya olabilir. Bu tasarımda script dosya olacaktır. İçeriği aşağıdaki gibi olacaktır.
cat > initrd/init << EOF
#!/bin/busybox ash
PATH=/bin
/bin/busybox mkdir -p /bin
/bin/busybox --install -s /bin
#**********************************
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
[ -d /dev ] || mkdir -m 0755 /dev #/dev dizini yoksa oluştur
[ -d /root ] || mkdir -m 0700 /root #/root dizini yoksa oluştur
[ -d /sys ] || mkdir /sys #/sys dizini yoksa oluştur
[ -d /proc ] || mkdir /proc #/proc dizini yoksa oluştur
mkdir -p /tmp /run # /tmp ve /run dizinleri oluşturuluyor
# sisteme dizinler bağlanıyor(yükleniyor)
mount -t devtmpfs devtmpfs /dev
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t tmpfs tmpfs /tmp
systemd-udevd --daemon --resolve-names=never #modprobe yerine kullanılıyor
udevadm trigger --type=subsystems --action=add
udevadm trigger --type=devices --action=add
udevadm settle || true
mkdir -p disk # /dev/sda1 diskini bağlamak için dizin oluşturuluyor
modprobe ext4 #ext4 modülü yükleniyor harici olarak yüklememiz gerekiyor
mount /dev/sda1 disk #diski bağlayalım
# dev sys proc taşıyalım
mount --move /dev /disk/dev
mount --move /sys /disk/sys
mount --move /proc /disk/proc
exec switch_root /disk /sbin/init #sistemi initrd içindeki initten sda1 diskinde olan /sbin/init'e devrediyoruz.
/bin/busybox ash #eğer üst satırdaki görev devir işlemi olmazsa bu satır çalışacak ve tty açılacaktır.
EOF
chmod +x initrd/init #init dosyasına çalıştırma izni veriyoruz.
cd initrd
find |cpio -H newc -o >initrd.img # initrd.img dosyasını initrd dizinine oluşturacaktır.|
cd ..
Oluşturulan initrd.img dosyası çalışacak tty açacak(konsol elde etmiş olacağız. Aslında bu işlemi yapan şey busybox ikili dosyası.
S15- distro/iso/initrd.img - S16- distro/iso/vmlinuz¶
initrd.img dosyası kernel(vmlinuz) ile birlikte kullanılan belleğe ilk yüklenen dosyadır. Bu dosyanın görevi sistemin kurulu olduğu diski tanımak için gereken modülleri yüklemek ve sistemi başlatmaktır. Bu dosya /boot/initrd.img-xxx konumunda yer alır. initrd.img dosyası üretmek için
cp /boot/vmlinuz-$(uname -r) iso/boot/vmlinuz #sistemde kullandığım kerneli kopyaladım istenirde kernel derlenebilir.
mv initrd/initrd.img iso/boot/initrd.img #daha önce oluşturduğumuz **initrd.img** dosyamızı taşıyoruz.
S17- distro/iso/grub/grub.cfg¶
grub menu dosyası oluşturuluyor.
cat > iso/boot/grub/grub.cfg << EOF
linux /boot/vmlinuz
initrd /boot/initrd.img
boot
EOF
Yukarıdaki script iso/boot/grub/grub.cfg dosyasının içeriği olacak şekilde ayarlanır.
İso Oluşturma¶
grub-mkrescue iso/ -o distro.iso #iso doyamız oluşturulur.
Artık sistemi açabilen ve tty açıp bize suna bir yapı oluşturduk. Çalıştırmak için qemu kullanılabililir.
qemu-system-x86_64 -cdrom distro.iso -m 1G komutuyla çalıştırıp test edebiliriz.
Bağımlılıkların Tespiti¶
İkili dosyasının iki tür derlenme şekli vardır(statik ve dinamik). Statik derleme gerekli olan kütüphaneleri içerisinde barındıran tek bir dosyadır. Dinamik olan ise gerekli olan kütüphane dosyaları ikili dosya dışında tutulmaktadır. İkili dosyamızın bağımlılıklarının bulunması için aşağıdaki scripti kullanabiliriz. Scripti lddscript.sh dosyası olarak kaydedip kullanabilirsiniz. bash lddscript.sh /bin/ls /tmp/test şeklinde kullandığımızda /tmp/test/ dizinine ls ikili dosyasının konumunu ve bağımlılıklarını kopyalayacaktır.
#!/bin/bash #bash lddscript binaryPath binaryTarget if [ ${#} != 2 ] then echo "usage $0 PATH_TO_BINARY target_folder" exit 1 fi path_to_binary="$1" target_folder="$2" # if we cannot find the the binary we have to abort if [ ! -f "${path_to_binary}" ] then echo "The file '${path_to_binary}' was not found. Aborting!" exit 1 fi # copy the binary itself ##echo "---> copy binary itself" ##cp --parents -v "${path_to_binary}" "${target_folder}" # copy the library dependencies echo "---> copy libraries" ldd "${path_to_binary}" | awk -F'[> ]' '{print $(NF-1)}' | while read -r lib do [ -f "$lib" ] && cp -v --parents "$lib" "${target_folder}" done