|
|
Können Sie den Zeitpunkt schon erkennen, an dem Ihre über's Netz verstreuten Dateisysteme mit dem bisherigen Konzept nicht mehr zu sichern sind? Uns ging es ebenso. Weil kommerzielle Systeme zu teuer waren, entwickelte ich mit existenten Werkzeugen, wie awk, rsh, rdump und der Bourne-Shell, einen simplen Mechanismus, mit dem wir unseren Backup realisieren.
In unserem heterogenen UNIX-Netz, bestehend aus NeXTen, Sun3s, Sun4s und einer Celerity, sind ca. 70 Dateisysteme mit etwa 7 GB an Datenvolumen zu sichern. Davon sind ca. 4 GB Benutzerdaten, die täglich, und ca. 3 GB Systemdaten, die einmal wöchentlich gesichert werden sollten. Als Backup-Medium steht ein Exabyte mit 5 GB fassenden Bändern zur Verfügung.
Da sich in unserem Netz die Struktur der Dateisysteme semesterweise ändert, muß der Mechanismus leicht an jede wahrscheinliche Konfiguration anpaßbar sein. In Zukunft wird sich in unseren Rechner-Zoo noch eine weitere Gattung einschleichen, was bedeutet, daß der Mechanismus keine speziellen Eigenschaften des bestehenden Netzes nutzen kann. Damit der Betrieb tagsüber ungestört ist, muß der Backup nachts und demzufolge ohne Bedienung als Batch-Job ablaufen.
Weil wir Rechnerbetrieb als Hobby betreiben, stand für die Entwicklung sehr wenig Zeit zur Verfügung. Um den Entwicklungsaufwand in Grenzen zu halten, wurden wann immer möglich, existente Programme eingesetzt. Die reine Entwicklungszeit betrug ca. 8 Stunden.
Das Backup-Skript wird vom Benutzer backup auf dem Rechner, an dem das Exabyte physikalisch angeschlossen ist, gestartet. Durch den Inhalt der Datei dump_table wird gesteuert, welche Dateisysteme von welchen Rechnern an welchem Tag gesichert werden sollen, siehe Abbildung 1.
$ head dump_table [1] thor:/dev/root [1] thor:/dev/usr [02-6] thor:/dev/export [02-6] thor:/dev/home [1] thor:/dev/l_export [1] iduna:/dev/usr [02-6] iduna:/dev/export [1] frigga:/dev/root [1] frigga:/dev/usr /usr [02-6] frigga:/dev/export [1] garm:/dev/root
Die erste Spalte von dump_table gibt an, an welchen Tagen das in der zweiten Spalte stehende physikalische Dateisystem gesichert werden soll. Als Indikatoren für den Wochentag wurden Ziffern gewählt, um die Datei übersichtlich zu halten und Bereichsangaben leichter mit awk bearbeiten zu können. Für date +%w beginnt die Woche mit dem Tag 0 am Sonntag.
Diese Datei muß unter allen Umständen mit dem Zustand des Netzes übereinstimmen, was die Verbindung zwischen Montagepunkt des Dateisystems und dem entsprechenden Rechner betrifft. Die Daten, die dieser Datei zugrunde liegen, sind auf dem Netz, wenn auch verstreut, vorhanden. c_dump_t sammelt die einzelnen /etc/fstabs der Rechner unseres Netzes auf und generiert dump_table, siehe Abbildung 2.
#!/bin/sh
# c_dump_t - generiert eine Rohversion der Tabelle,
# nach der backup sichert.
#
. shell_lib.a # Globale Variablen & fatal & test_...
usage="usage: `basename $0`" # Aufruf
DUMP_TABLE=${DUMP_TABLE}.new # pro Zeile ein Eintrag
case "$#"
in 0) break;
;; *) fatal "$usage"
esac
# Falls $0 zweimal zur gleichen Zeit laeuft, gibt's Aerger.
/etc/link "$HOME/bin/`basename $0`" "$LOCK" ||
fatal "`basename $0` in use; try again"
trap 'rm -f "$LOCK"; exit' 0 1 2 3 13 14 15 # Aufraeumaktionen
test_and_create_dir $FSTABS # Falls nicht vorhanden generieren
hosts=`gethostname "inf"` # alle Rechner der Netzgruppe 'inf'
for i in $hosts # alle fstabs aufsammeln
do
rcp $i:/etc/fstab $FSTABS/$i # wegen grep
case $?
in 1) fatal "$0: \"rcp $i:/etc/fstab $FSTABS/$i\" failed"
;; 0) chmod 666 $FSTABS/$i # wegen Ueberschreiben
esac
done
cd $FSTABS
# [\tBlank]
grep "^\/dev\/" * | sed 's/[ ].*//' >> $TOP/$DUMP_TABLE
exit 0
Dadurch ist eine Inkonsistenz zwischen dem Zustand des Netzes und dump_table nahezu ausgeschlossen.
Um Funktionen und Werte, die in mehreren Skripten verwendet werden nur an einer Stelle pflegen zu müssen, werden diese in eine Shell-Bibliothek ausgelagert. Diese Bibliothek wird in den entsprechenden Skripten durch das .-Kommando ausgewertet, siehe Abbildung 3.
#!/bin/sh
#
# shell_lib.a
#
TOP=/home/backup # Katalog
FSTABS=$TOP/Fstabs # Die Fstabs aller Rechner
LOCK=$TOP/.lock # entweder backup oder c_dump_t
DUMP_TABLE=$TOP/dump_table # pro Zeile ein Eintrag
TAPE=/dev/nrst1 # das Exabyte
HEADER=header
#
fatal() # message
{ echo >&2 `basename $0`: "$@"
exit 1
}
test_and_create_dir() # dir
{ if [ ! -d $1 ]
then
echo "Warning: $1 does not exist."
mkdir $1
fi
}
dump_table ist die einzige Datei, die vom Systemadministrator gepflegt werden muß. Die Arbeit beschränkt sich allerdings auf die Festlegung, an welchem Tag ein Dateisystem gesichert werden soll. Die einfache Struktur dieser Datei verringert die Gefahr eines fehlerhaften Eintrags.
Das backup-Skript läuft auf dem Exabyte-Server mit den Berechtigungen eines normalen Nutzers. Würde man das Skript als root starten, müßte der Exabyte-Server für jeden Rechner, dessen lokale Platte gesichert werden soll, als vertrauenswürdig erscheinen. Dies erschien mir als unnötig und zu risikoreich.
Der Algorithmus des Skripts ist trivial:
Für jede Zeile von dump_table wird auf dem
entsprechenden Rechner
ein rdump-Kommando
der Form
/etc/rdump ${LEVEL}ufs $EXA_SERVER:/dev/nrst1
mit root-Berechtigung abgesetzt.
Ist dump_table abgearbeitet,
wird verifiziert,
ob der Backup für alle Dateisysteme erfolgreich war,
falls nicht,
wird der Systemadministrator via mail informiert.
Wie sorgt man nun dafür, daß rdump auf den unterschiedlichen Architekturen unter root-Berechtigungen abläuft? Mit dem dazwischen geschaltenen Shell-Skript execS, siehe Abbildung 4.
#!/bin/sh
#
# execS fuehrt $@ unter euid = uid = 0
# auf Sun[34], NeXT oder Celerity aus.
#
# Beware of:
# -rwsr-xr-x 1 root 106496 Jan 18 11:57 *equal
# ....
PATH=:/usr/lbin:/usr/bin:$HOME/bin:/home/backup/bin:$PATH
case `arch`
in "sun4") echo " $@" | $HOME/bin/Sun4equal; break
;; "sun3") echo " $@" | $HOME/bin/Sun3equal; break
;; "NeXT") echo " $@" | $HOME/bin/Nextequal; break
;; "celerity") echo " $@" | $HOME/bin/Celerityequal; break
;; *) exit 1 # Generiere *equal aus .../Src/equal.c
esac
Abhängig von der Architektur aktiviert execS ein kleines C-Programm *equal, das die effektive und wirkliche Benutzernummer auf 0 setzt, mit execl, die Shell aufruft, die dann von Standardeingabe das entsprechende Kommando liest und abarbeitet, siehe Abbildung 5.
/*
* setzt die euid = uid = 0.
*/
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <strings.h>
#define BACKUP "backup"
main()
{
uid_t uid;
uid_t euid;
struct passwd * pp;
if ( ! (pp = getpwuid(getuid()) ) ) {
fprintf(stderr," getpwuid failed\n");
exit(1);
}
if ( strcmp(pp->pw_name, BACKUP ) )
exit(1);
if ( setreuid(0,0) == -1 ) {
fprintf(stderr," setregid failed\n");
exit(1);
}
execl("/bin/sh", "/bin/sh", (char *)0);
}
Um das Sicherheitsloch in Grenzen zu halten, überprüft *equal wer der Aufrufende ist. Bei jedem anderen als backup terminiert das Kommando vor Ausführung des kritischen Aufrufs.
Es reicht nicht, nur die effektive uid auf 0 zu setzen, da Suns rdump überprüft, ob uid = euid ist. Deshalb genügt es nicht, eine Kopie von /bin/sh mit den entsprechenden Rechten auszustatten.
Für die kurze Zeit des Kommunikationsaufbaus wird auf dem Exabyte-Server arrangiert, daß der Rechner dessen Dateisystem als nächstes gesichert werden soll, als vertrauenswürdig gilt.
Der wesentliche Teil von backup ist in Abbildung 6 abgebildet.
ex_dump_l $DUMP_TABLE | \
sed 's/[ ].*//' | \
sed 's/:/ /' | \
while read Host Rdev
do
rsh -n $Host $HOME/bin/execS $DumpCmd ${LEVEL}ufs \
$Dumphost:$TAPE $LENGTH $Rdev
done
ex_dump_l extrahiert die an diesem Tag zu sichernden Zeilen.
Wir sichern prinzipiell alle Daten der Dateisysteme. Inkrementelle Sicherungen bringen uns keinen Vorteil, da auf alle Fälle ein Band benötigt wird, das bisher genügend Platz für einen kompletten Backup bieten. Da die Sicherung von 4 GB Daten ungefähr 6 Stunden dauert, reicht die Nacht zum Sichern der Daten aus. Die Restaurierung verlorengegangener Daten ist für uns aus vollständigen Sicherungen einfacher, als wenn wir inkrementell sichern würden. Das Skript wird an allen Arbeitstagen von Hand gestartet. In Abbildung 7 ist ein typischer Ablauf abgebildet.
loki backup 72 backup Tape number = 20 Sleep for ?? seconds: 15000 I hope 15000 is ok. loki backup 72
Von jedem beschriebenen Band existiert eine Datei, in welcher der Verlauf des Backups protokolliert ist. Auftretende Fehler können so analysiert und falls möglich behoben werden.
In einer zweiten Datei stehen mt-Anweisungen, mit denen man bis zu der Stelle, an der das gesicherte Dateisystem zu finden ist, vorspulen kann, siehe Abbildung 8.
On Volume: 20 ======================== mt -f /dev/nrst1 fsf 0 DUMP echo thor:/dev/export ------------- backup on sun4 was ok mt -f /dev/nrst1 fsf 1 DUMP echo thor:/dev/home ------------- backup on sun4 was ok mt -f /dev/nrst1 fsf 2 DUMP echo dosuni:/dev/export ------------- backup on sun4 was ok ...
Diese Anweisungen erleichtern ein Restaurieren erheblich, denn auf einem Band können bis zu 40 Dateisysteme gesichert sein. Die eigentliche Restaurierung muß via restore in die Wege geleitet werden. Da dies bei uns selten vorkommt, erschien mir eine weitere Unterstützung unnötig.
In aller Regel funktioniert unser Backup problemlos. Ab und zu blockiert unser Exabyte den SCSI-Bus des Exabyte-Servers, was dann dazu führt, daß manuell eingegriffen werden muß. Dies ist allerdings ein Problem das weniger auf den Backup-Mechanismus, als vielmehr auf das Exabyte zurückzuführen ist.
Was uns noch fehlt, ist ein Programm, das die Bandverwaltung übernimmt, damit Verwechslungen von Bändern ausgeschlossen werden können.
Der Mechanismus hat sich bei uns bewährt. Der Aufwand an menschlicher Arbeitskraft, die bisher nötig war, um den Backup zu ziehen, wurde wesentlich reduziert. Die Entwicklungszeit hat sich um ein Vielfaches ausbezahlt. Die fehlende Graphikoberflächen, die man sich denken kann, wurde bisher noch nicht vermißt.
|
|
Last modified 03/July/97