Linux CD-ROM Router
InitRD
Der CD-ROM-Router startet mit einer geschickt angelegten initialen RAM-Disk. Dieses Kapitel erläutert, wie diese gemacht wird.
cdmount
bin/mount können wir nicht nehmen, da dieses dynamisch mit
libc gelinkt ist und diese zu groß für eine InitRD ist. Wir behelfen
uns mit einem kleinen C-Programm, daß ich dem
cdmount.c:
#include <sys/mount.h>
main(int argc, char ** argv)
{
int data = 0;
return mount(argv[1],argv[2],argv[3],MS_RDONLY|MS_MGC_VAL,&data);
}
cdmount.c muß mit den folgenden Optionen übersetzt werden. Wichtig
ist, daß es statisch gelinkt wird und die Symboltabellen abgetrennt
werden.
gcc -O2 -static -s -o /tmp/cdmount cdmount.c
Zum Test kann es wie folgt aufgerufen werden:
# /tmp/cdmount /dev/cdrom /mnt/cdrom iso9660
# cat /proc/mounts
Wenn eine CD-ROM normal eingehängt wird, ist es in Ordnung.
cdmount in Assembler (2001-01-20)
Obwohl cdmount nur ein sehr kleines Programm ist, so ist das erzeugte Binärprogramm auf meinem Rechner doch 219828 Byte groß geworden. Über die Ursache will ich mich an dieser Stelle nicht auslassen, aber nach einer Alternative habe ich mich schon umgesehen. Dann fand ich Robin Miyagis wunderbares
LINUX ASSEMBLER TUTORIAL mit dessen Hilfe ich die folgende Alternative basteln konnte, die genau das gleiche macht wie das C-Programm, aber nur ein 412 Byte großes Binary erzeugt.
## cdmount.s ###################################################
## Mathias Weidner ############################################
## http://weidner.in-bad-schmiedeberg.de/ ######################
## This file contains minimal program to mount a CD.
##
## It takes three arguments: device, mount point, filesystem
##
## example:
## cdmount /dev/cdrom /mnt/cdrom iso9660
## Compile Instructions:
## -------------------------------------------------------------
## as -o cdmount.o cdmount.s
## ld -O0 -o cdmount cdmount.o
########################################################################
.section .data
.align 4
mountdata:
.long 0
########################################################################
.section .text
.globl _start
.align 4
_start:
movl %esp, %ebp # store %esp in %ebp
_mount:
addl $8, %esp # %esp ---> second parameter on stack
movl (%esp), %ebx # move next parameter into %ebx
addl $4, %esp # %esp ---> third parameter on stack
movl (%esp), %ecx # move next parameter into %ecx
addl $4, %esp # %esp ---> fourth parameter on stack
movl (%esp), %edx # move next parameter into %edx
movl $0xc0ed0001, %esi # MS_MGC_VAL|MS_RDONLY ---> %esi
leal mountdata, %edi # pointer to 0
movl $21, %eax # system call _mount
int $0x80
_exit:
movl %eax, %ebx # give back return value
xorl %eax, %eax # %eax = 0
incl %eax # %eax = 1, system call _exit ()
int $0x80 # execute _exit () system call
## end of cdmount.s ############################################
initrd.img
Zum Erzeugen einer initialen RAM-Disk für den Systemstart gibt es bei
RedHat das Programm sbin/mkinitrd. Die damit erzeugte InitRD
muß noch etwas angepaßt werden.
mkinitrd kopiert die sash auf die InitRD. Diese Shell ist zwar
für interaktive Bootdisketten recht komfortabel durch die vielen
eingebauten Kommandos, doch leider fehlen Ihr die meisten Bourne-Shell
Programmiermöglichkeiten, so daß wir diese entfernen und stattdessen
die ash (statisch gelinkte Version) verwenden.
Konkret wird die InitRD wie folgt angepaßt:
---
# /sbin/mkinitrd -v -f /boot/initrd-cd-rom.img 2.2.16-3
# zcat /boot/initrd-cd-rom.img > /tmp/initrd-cd-rom
---
# mkdir /mnt/tmp
# mount -o loop /tmp/initrd-cd-rom /mnt/tmp
# cd /mnt/tmp/bin
# rm sash
# cp -p /bin/ash.static sh
# cd ..
# mkdir -p mnt/{cdrom,floppy,dev}
# mv bin dev lib mnt/cdrom
# mv etc mnt/floppy
# ln -s mnt/cdrom/* .
# ln -s mnt/floppy/* .
# ln -s mnt/cdrom/usr mnt/cdrom/sbin mnt/cdrom/var mnt/cdrom/root .
# touch fastboot
# for i in 0 1 2 3 4 5 6 7 8 9; do mknod mnt/dev/tty$i c 4 $i; done
# mkdir proc
# mkdir tmp
# chmod 1777 tmp
# cp -a /dev/hd[abcd]* /dev/scd0 /dev/sda* mnt/cdrom/dev
# cp -p /tmp/cdmount .
# vi linuxrc # siehe unten über linuxrc
# cd /
# umount /mnt/tmp
# gzip -9 < /tmp/initrd-cd-rom > /boot/initrd-cd-rom.img
linuxrc
Wir fügen ein paar Befehle in linuxrc wie folgt ein. Dort stehen
bereits ein paar Zeilen, die durch mkinitrd geschrieben wurden,
aber diese können wir stehen lassen.
linuxrc:#! /bin/sh echo "Loading aic7xxx module insmod /lib/aic7xxx.o /cdmount /dev/hdc /mnt/cdrom iso9660 \ || /cdmount /dev/hdd /mnt/cdrom iso9660 \ || /cdmount /dev/hdb /mnt/cdrom iso9660 \ || /cdmount /dev/scd0 /mnt/cdrom iso9660 \ || ( echo 'cannot mount CD-ROM, invoke /bin/sh' /bin/sh ) mount /dev/fd0 /mnt/floppy \ || mount -o loop -t ext2 /mnt/cdrom/boot.img /mnt/floppy mount -t proc none /proc echo 0x100 > /proc/sys/kernel/real-root-dev umount /proc
Layout der InitRD
Nun müßte der Verzeichnisbaum in der InitRD wie folgt aussehen:
/etc -> mnt/floppy/etc
/sbin -> mnt/cdrom/sbin
/bin -> mnt/cdrom/bin
/usr -> mnt/cdrom/usr
/lib -> mnt/cdrom/lib
/var -> mnt/cdrom/var
/dev -> mnt/cdrom/dev
/root -> mnt/cdrom/root
/
/tmp/var/lock/
/run/
/proc/
/
/linuxrc
/cdmount
/fastboot
/
/mnt/cdrom/bin/sh
/ / /insmod
/ /
/ /lib/aic7xxx.o
/ /
/ /dev/console
/ /null
/ /hdc
/ ...
/floppy/etc
Die Verzeichnisse, die von mkinitrd angelegt wurden, sind unter
&/;mnt/cdrom verschoben und durch symbolische Links ersetzt. Unter
&/;mnt/cdrom sind die minimalen Dateien, die benötigt werden,
bevor die CD-ROM eingehängt wird. Die Konfigurationsdaten von
&/;etc werden von der Bootdiskette genommen, die unter
&/;mnt/floppy eingehängt wird. Damit kann die Konfiguration auf
einer Diskette geändert werden, ohne daß lilo jedesmal aufgerufen
werden muß.
In linuxrc wird der cdmount Befehl verwendet um die CD-ROM
einzuhängen. Dabei werden nacheinander /dev/hdc,hdd,hdb,scd0 probiert,
bis die CD-ROM montiert werden kann. Sobald die CD-ROM eingehängt ist,
stehen alle Kommandos von der CD-ROM zur Verfügung. Wenn keine CD-ROM
montiert werden kann, wird eine Shell gestartet und die Nachricht
ausgegeben. Damit kann zu Testzwecken eine Festplatte eingehängt
werden bevor eine richtige CD-ROM gebrannt wird.
Nachdem die CD-ROM montiert wurde, wird unter &/;mnt/floppy versucht eine Diskette zu montieren. Schlägt dieses fehl, wird die Datei boot.img aus der Wurzel der CD-ROM genommen. Damit stehen die Konfigurationsdateien zur Verfügung.
Schließlich wird das &/;proc Dateisystem eingehängt und
0x100 (das ist die Gerätenummer der InitRD) in real-root-dev
geschrieben um festzulegen, daß die InitRD selbst als Rootdateisystem
fungiert.
Außerdem gibt es eine Datei fastboot in der InitRD, um die Überprüfung der Dateisysteme laut fstab zu unterbinden.
Wenn alle Änderungen an initrd-cd-rom eingetragen sind, wird diese
ausgehängt, mit gzip komprimiert und als
&/;boot/initrd-cd-rom.img abgelegt.
Boot Test für initrd-cd-rom.img
Nun sollte die InitRD für die CD-ROM fertig sein. Diese können wir mit LILO und der Festplatte testen. Dazu fügen wir die folgenden Zeilen an &/;etc/lilo.conf an:
image = /boot/vmlinuz-2.2.16-3 label = cd-rom initrd = /boot/initrd-cd-rom.img root = 0x101 # das darf nicht 0x100 sein, der # eigentliche Wert ist egal
Dann installieren wir LILO.
# /sbin/lilo Added linux * Added cd-rom
Nun haben wir einen Boot Test mit der Festplatte. Wir legen noch keine
CD-ROM ein. Nach dem Neustart geben wir cd-rom beim Prompt von LILO
ein. Nachdem vmlinuz und initrd-cd-rom geladen sind
landen wir in einer Shell und können die Festplatte wie folgt
einhängen:
# /cdmount /dev/hda1 /mnt/cdrom ext2
=========
|
+---- durch die korrekte Partition ersetzen.
Indem wir die Festplatte read-only einhängen, überprüfen wir, ob sie
als CD-ROM geeignet ist. Nach dem Aufruf von cdmount sollten
die üblichen UNIX-Befehle wie z.B. ls verfügbar sein.
Wenn wir die Shell verlassen, wird linuxrc beendet und
sbin/init erlangt die Kontrolle über den Rechner.