slick Bodhisattva
Joined: 20 Apr 2003 Posts: 3495
|
Posted: Sun Jan 07, 2007 6:08 pm Post subject: Tipp: / readonly (für Router / kleine Server) |
|
|
Ich hatte mir http://gentoo-wiki.com/HOWTO_Read-only_root_filesystem angeschaut um / meines Router readonly zu mounten. Leider habe ich keine extra Partition für z.B. /etc und die zweite Variante mit /etc/mtab scheint mir etwas kompliziert. Meine Variante braucht nur minimale Anpassungen und läßt sich zur Laufzeit von root wieder rückgängig machen. Sie hat allerdings keinen Anspruch auf Vollständigkeit.
Hier meine Vorgehensweise, die sich eignet für kleine Systeme ohne X wie etwa kleine Server oder Homerouter, was den Vorteil hat das nach einem Stromausfall (wahrscheinlich) kein fsck laufen braucht. Das ist gerade von Vorteil wenn der Rechner ausschließlich remote administriert wird und Dateisystemfehler die häufigste Ursache sind wenn der Rechner nicht mehr sauber von allein hochfährt. Auf solchen Systemen gibt es meist keine weiteren User-Accounts, sodaß hier nicht auf die Konfiguration eingegangen wird die nötig wäre wenn sich Benutzer (außer root) anmelden möchten.
Das Prinzip funktioniert so: Wir schmuggeln etwas Code in das Initscript ein welches / mountet und somit brauchen wir auch keine initrd o.ä. sondern gaugeln dem System vor alles wäre wie sonst. Ggf. muss das Vorgehen angepaßt werden wenn bestimmte Services laufen.
Wir legen auf / ein leere Verzeichnis an, hier als Beispiel /new
Wir legen folgendes Script, hier als Beispiel /sbin/readonlymount, an
Code: | #!/bin/sh
PATH="/bin:/usr/bin:/sbin:/usr/sbin"
# / readonly mounten
mount -o ro `mount -vf -o remount /|cut -d " " -f 1` /
# Ramdisk erstellen
mount -t tmpfs none /new
# folgende Verzeichnisse werden in der Ramdisk anlegen
DIR="/etc
/root
/var/run
/var/log
/var/lock
/var/lib
/tmp"
# pro Verzeichnis dieses in der Ramdisk anlegen, Original reinkopieren und in / einhängen
for dir in $DIR ; do
mkdir -p /new/${dir}
cp -a ${dir}/* /new/${dir}
cp ${dir}/.* /new/${dir}
mount -o bind /new/${dir} /${dir}
done
# hier noch ggf. anpassen von Dateirechten
#chown foo:bar /dir
#chmod $$$ /dir
exit 0 |
Natürlich könnte man auch unionfs benutzen um die benötigten Verzeichnisse rw zu mounten, allerdings paßt unionfs nicht zu jedem Kernel und ist auch nicht ganz so schnell wie eine reine Ramdisk. Geschwindigkeit ist aber hier meist egal, ist halt Geschmackssache sag ich mal. Unionsfs würde dafür aber Ram einsparen falls dieser sehr knapp ist.
Wir machen das Script ausführbar.
Code: | chmod +x /sbin/readonlymount |
Als nächstes bearbeiten wir die Datei /etc/init.d/checkroot. Zuerst legen wir eine Sicherungskopie an, besser ist das
Code: | cp /etc/init.d/checkroot /root/checkroot.backup |
Nun suchen wir in der Datei folgenden Block:
Code: | # Should we mount root rw ? the touch check is to see if the / is
# already mounted rw in which case there's nothing for us to do
if mount -vf -o remount / 2> /dev/null | \
awk '{ if ($6 ~ /rw/) exit 0; else exit 1; }' && \
! touch -c / >& /dev/null
then
ebegin "Remounting root filesystem read/write"
mount -n -o remount,rw / &> /dev/null
if [[ $? -ne 0 ]] ; then
eend 2 "Root filesystem could not be mounted read/write :("
if [[ ${RC_FORCE_AUTO} != "yes" ]] ; then
/sbin/sulogin ${CONSOLE}
fi
else
eend 0
fi
fi |
Diesen Block lassen wir wie er ist, umschliessen ihn nur mit einer if-Abfrage
Code: | if cat /proc/cmdline | grep "makereadonly" &> /dev/null ; then
# Pfad zu unserem Script:
/sbin/readonlymount
else
# Should we mount root rw ? the touch check is to see if the / is
# already mounted rw in which case there's nothing for us to do
if mount -vf -o remount / 2> /dev/null | \
awk '{ if ($6 ~ /rw/) exit 0; else exit 1; }' && \
! touch -c / >& /dev/null
then
ebegin "Remounting root filesystem read/write"
mount -n -o remount,rw / &> /dev/null
if [[ $? -ne 0 ]] ; then
eend 2 "Root filesystem could not be mounted read/write :("
if [[ ${RC_FORCE_AUTO} != "yes" ]] ; then
/sbin/sulogin ${CONSOLE}
fi
else
eend 0
fi
fi
fi |
Die Abfrage hat den Vorteil das wir über einen frei wählbaren Kernelparameter das Verhalten des Initscript steuern können. Übergeben wir beim booten den Parameter "makereadonly" wird das System mit Hilfe des Scriptes readonly gemountet, ohne dem Parameter verhält sich das System wie normal.
Anschliessend wird im Bootlader noch eine zweite Boot-Option erstellt und der Parameter "makereadonly" hinzugefügt.
Beispiel Lilo:
Code: | image = /boot/vmlinuz
label = Readonly
root = /dev/hda3
append = "makereadonly"
optional |
Beispiel Grub:
Code: | title=Readonly
root (hd0,0)
kernel (hd0,0)/vmlinuz root=/dev/hda3 makereadonly |
Wenn alles funktioniert braucht im Bootloader nur der Default-Boot so gesetzt werden.
Hinweise
- /etc/fstab braucht nicht editiert werden, keinesfalls ro in der /etc/fstab setzen
- mount zeigt / fälschlicherweise als rw gemountet an, ein touch /foo belehrt uns aber eines besseren
- braucht man / mit Schreibrechten muß ausgeführt werden: mount -o remount,rw /
- man bedenke das alle Änderungen in den Ramdisk (z.B. /etc) usw. nur Wirkung bis zum nächsten Reboot haben
- man sollte über ein Notfallsystem verfügen (z.B. booten von CD-Rom) denn falls was schiefgeht bootet das System nicht mehr bis zum Prompt
- ggf. hat man mit obigen Script ein paar Fehlermeldungen (z.B. kopieren von leeren Verzeichnissen), diese können wenn alles funktioniert nach /dev/null umgeleitet werden (z.B. cp ... &> /dev/null)
- die oben angebenen Verzeichnisse sollten geprüft werden ob sie überhaupt entsprechend klein sind und in die Ramdisk passen würden (du -sh /var/lib) , ansonsten muss die Verzeichnisliste verfeinert werden
|
|