Disketten für User und von ihnen über das
Netz mounten
Inhalt
Die Aufgabe
Es geht darum, daß Usern von einem Rechner ohne Diskettenlaufwerk
die Möglichkeit gegeben wird, an einem anderen Rechner im LAN das
Diskettenlaufwerk so zu nutzen, als wäre es lokal vorhanden. Der User
soll die Diskette in den Rechner einlegen der ein Laufwerk hat, dann
zu seinem Rechner gehen und nach dem Aufruf eines Befehls sollen ihm die
Dateien auf der Diskette zur Verfüging stehen. Ist der User mit seiner
Arbeit fertig, soll er nach Eingabe eines Kommandos die Diskette am entfernten
Rechner wieder entnehmen können.
Die Realisierung
Das Beispielnetzwerk
Der
Aufbau des Netzwerkes ist in der Abbildung dargestellt.
Um eine größere Abbildung des Beispielnetzwerkes zu erhalten,
bitte auf das Bild klicken.
Damit ergibt sich die folgende Konstellation:
-
Rechner mit Diskettenlaufwerk: foo.mynet.org, IP-Adresse: 172.16.2.1
-
Rechner ohne Diskettenlaufwerk: bar.mynet.org, IP-Adresse: 172.16.2.2
-
Es handelt sich um ein geswitchtes Netz.
-
Die Anbindung an das Internet erfolgt über einen Router (rou.mynet.org)
-
Der Router im LAN-Bereich: rou.mynet.org, IP-Adresse: 172.16.2.4
-
Der WAN/Internetteil des Routers ist uninteressant (an dieser Stelle)
-
Netzwerkmaske im LAN: 255.255.0.0 (Standard Class B)
-
Netzwerkadresse im LAN: 172.16.0.0 (Standard Class B)
-
Die Rechner haben als Defaultgateway den Router eingetragen
Kombination aus mount und nfs
Um die Aufgabe zu lösen, wird eine Kombination aus lokalem Mounten
(an foo) und aus Mounten per NFS (von foo an bar) benutzt. Dazu sind die
folgenden schritte notwendig:
-
Diskette lokal an foo mounten
-
Mountpoint der Diskette von foo exportieren
-
bar muß Mountpoint der Diskette an foo über das Netz per NFS
mounten
Beim Abmounten ist die umgekehrte Reihenfolge einzuhalten. Um dieses erfolgreich
durchführen zu können, benötigt man einen Kernel mit Unterstützung
für vfat/msdos und nfs.
Die Einstellungen am Rechner mit Diskettenlaufwerk
(foo)
Zuerst muß die Datei /etc/fstab angepaßt werden, damit
der defaultmäßige Mountpoint der Diskette bekannt ist und jeder
User die Diskette mounten kann.
Dazu muß die Datei /etc/fstab die folgende Zeile enthalten:
/dev/fd0 /floppy vfat noauto,sync,user 0 0
Diese Zeile soll nur kurz erläutert werden:
-
die Gerätedatei des Diskettenlaufwerkes ist /dev/fd0
-
die Diskette soll an /floppy gemountet werden
-
das Dateisystem auf der Diskette ist vfat (DOS & WIN)
-
noauto: nicht beim Booten automatisch mounten
sync: Zugriffe sofort synchronisieren
user: jeder User darf die Diskette mounten
Anschließend muß man dafür sorgen, daß das Verzeichnis
floppy über das Netzwerk an andere Rechner exportiert werden kann.
Dazu ist der folgende Eintrag in der Datei /etc/exports notwendig:
/floppy bar(rw)
Die hier gezeigte Einstellung ist die Einfachste der möglichen Kombinationen.
Weitere Einstellungen sind der Manpage von exports zu entnehmen. Der Eintrag
bedeutet das Folgende:
-
Das Verzeichnis /floppy wird exportiert
-
nur an den Rechner bar wird exportiert
-
der Rechner bar darf auf dieses Verzeichnis lesen und schreiben
Damit das Ganze dann wirklich funktioniert, muß noch der NFS-Daemon
gestartet werden. Dafür gibt es ab Kernel 2.1. mehrere Möglichkeiten.
Hier wird der einfachste Weg an Hand einer SuSE-Distribution gezeigt. Wir
gehen davon aus, daß man den hier beschriebenen Diskettenservice
immer anbieten will. Ist nur eine einmalige Aktion geplant, reicht es,
wenn man den NFS-Daemon mit
/sbin/init.d/nfsserver start
startet. Was man jetzt in jedem Fall erstmal tun sollte. Dabei wird der
Portmapper automatisch mitgestartet. Das Ganze läuft jetzt bis zum
nächsten reboot, init s, init 1 oder man mit
/sbin/init.d/nfsserver stop
den Daemon wieder anhält. Um den Daemon bei jedem Bootvorgang automatisch
mit zu starten, ist der folgende Eintrag in der Datei /etc/rc.config
notwendig:
NFS_SERVER="yes"
Defaultmäßig steht dieser auf "no".
So das war es nun aber wirklich schon - bis auf eine Ausnahme die weiter
unten bei den Skripten beschrieben wird.
Die Einstellungen am Rechner ohne Diskettenlaufwerk
(bar)
Das ist die einfachere Geschichte, da nur die Datei /etc/fstab angepaßt
werden muß. Es muß folgender Eintrag in /etc/fstab stehen:
foo:/floppy /mnt/remote_floppy nfs noauto,sync,user,rsize=8192,wsize=8192,timeo=14,intr
Der Großteil der Einträge ist bereits beim Mounten
der Floppy an foo erklärt worden. Der Rest bezieht sich auf reine
NFS-Einstellungen ist in der man-Page zu mount und fstab erläutert.
Damit sind an beiden Rechnern nun alle notwendigen Vorarbeiten geleistet.
Der erste Test
Zuerst muß an foo die Diskette gemountet werden. Dazu reicht das
Kommando:
mount /floppy
Danach sollte mit mount überprüft werden, ob die Diskette
auch gemountet ist.
/dev/fd0 on /floppy type vfat (rw,noexec,nosuid,nodev,sync,user=paul)
Hier hat also der User "paul" die Diskette erfolgreich gemountet. Ab diesem
Moment sollte nicht mehr versucht werden die Diskette aus dem Laufwerk
entfernt zu werden, da sonst das System etwas widerwillig reagiert. Anschließend
begibt man sich zum Rechner foo. Hier gibt man das entsprechende Mountkommando
mount /mnt/remote_floppy
ein. Sollte auch das erfolgreich sein, ergibt sich bei der Ausgabe von
mount
folgende Zeile:
foo:/floppy on /mnt/remote_floppy type nfs (rw,noexec,nosuid,nodev,sync,rsize=8192,wsize=8192,timeo=14,intr,addr=172.16.2.1,user=gustav)
Der User "gustav" hat die Diskette erfolgreich gemountet. Ab jetzt kann
er unter /mnt/remote_floppy auf die Daten der Diskette lesend und schreibend
zugreifen.
Was passiert wenn ...?
Generelles
Ein Verzeichnis - egal ob lokal gemountet oder per NFS - welches gerade
in Benutzung ist kann man nicht abmounten. Unter Benutzung versteht sich
hier jegliche Art von Nutzung - es reicht bereits aus, wenn sich jemand
per cd in diesem Verzeichnis befindet. Damit ist aber wiederum jeweils
nur die lokale Benutzung gemeint. Wenn gustav an bar folgendes macht:
cd /mnt/remote_floppy
Dann kann an foo der NFS-mount nicht aufgehoben werden - d.h.:
gustav@bar> umount /mnt/remote_floppy
ergibt:
umount: /mnt/remote_floppy: device is busy
Auf der anderen Seite kann aber der User paul an bar in dem Fall - vorausgesetzt
niemand befindet sich lokal an bar in dem Directory /floppy die Diskette
abmounten. Dies kann unabhängig davon geschehen, wie die Lage an bar
ist:
paul@foo> umount /floppy
führt also zum Erfolg. Damit sieht aber gustav an bar nicht mehr was
auf der Diskette ist! Aber paul an foo kann nun die Diskette wechseln und
erneut mounten. Nach diesem Mount - und einer evtl. geringen Wartezeit
- stehen gustav an bar die Daten der neuen Diskette unter /mnt/remote_floppy
zur Verfügung - ohne das er weiter etwas machen muß. Das Ganze
ist natürlich auch anders herum mach/denkbar:
-
gustav kann an bar den NFS-mount aufheben obwohl paul an foo die Diskette
lokal nicht abmounten kann, weil er z.B. mit cd /floppy in das
Directory gegangen ist.
An foo die Diskette abgemountet wird
Wenn gustav nun in sein Diskettendirectory (/mnt/remote_floppy) schreibt,
werden die Daten lokal auf der Platte von foo hinterlegt. Macht gustav
ein
ls /mnt/remote_floppy
bekommt er ein leeres Verzeichnis - oder Fehlermeldungen, daß die
bis dahin vorhandenen Dateien nicht mehr vorhanden sind. Hat paul die alte
- oder eine andere Diskette - wieder an foo /floppy gemountet, stehen nach
kurzer Zeit die Daten gustav wieder zur Verfügung. Sollte gustav aber
Daten auf der Platte von foo hinterlegt haben, so werden diese jetzt von
der gemounteten Diskette überdeckt. Um wieder an die Daten heranzukommen,
muß die Diskette also wieder (an foo) abgemountet werden.
So weit zur Verwirrung der Leserin/des Lesers ;-)
Nützliche Kommandos
Die jeweils lokalen mounts sieht man am Besten mit
Um zu erfahren, wie welchen Status man so als Client (wie bar in unserem
Fall) hat, benutzt man:
Schwieriger wird es, wenn man herausbekommen will wer gerade was von einem
per NFS gemountet hat. Hier gibt es:
-
/etc/rmtab (z.B. cat /etc/rmtab)
-
showmount (als root)
Aber: Die beide Möglichkeiten funktionieren nicht - oder nur
in Abhängigkeit von der jeweiligen Implementation!
Es kann aber sein, daß bei der Verwendung des Kernel-NFS-Daemons
die Sache anders aussieht - zumal dann auch noch der Weg über das
/proc-Filesystem besteht.
Die Automatisierung
Ziele
Eigentlich ist es weder gewünscht noch will der User so viel von den
Hintergründen wissen. Daher ist es das Ziel, daß der User eine
einfache Funktionalität bekommt, die darin besteht die Diskette per
Mausklick z.B. an bar zugänglich zu machen. Mit einem weiteren Klick
soll eine gefahrlose Entnahme der Diskette an foo ebenfalls möglich
sein. Vereinfacht wird ab jetzt davon ausgegangen, daß es sich
an bar um den User gustav handelt, der ebenfalls einen Account auf foo
(mit der gleichen USER-ID wie auf bar) hat.
Zusätzliches an foo
Wie bereits oben geschildert, muß zuerst die Diskette lokal an foo
gemountet werden. Dazu dient ein lokales Script an foo, was sich in dem
HOME-Directory des Users - oder aber im Pfad - befindet. Dieses Script
heißt floppy_local_mount.sh. Das Script ist nur wenige
Zeilen lang und hat folgenden Inhalt:
#!/bin/sh
MOUNT_POINT=/floppy
mount $MOUNT_POINT &>/dev/null
EXIT_CODE=$?
echo $EXIT_CODE
exit $EXIT_CODE
Nichts besonderes - bis auf die Tatsache daß der Exitcode des
mount-Kommandos mit echo angezeigt wird. Genau das ist aber wiederum doch
eine Besonderheit, wie wir später
noch sehen werden.
Natürlich gibt es noch ein Script zum Abmounten - floppy_local_umount.sh.
Es ist ebenfalls nur wenige Zeilen lang:
#!/bin/sh
MOUNT_POINT=/floppy
mount | grep -i $MOUNT_POINT &>/dev/null
EXIT_CODE=$?
if [ $EXIT_CODE == 0 ] ; then
# floppy ist gemountet
umount $MOUNT_POINT &>/dev/null
EXIT_CODE=$?
fi
echo $EXIT_CODE
exit $EXIT_CODE
Nach einem kurzen Check, ob die Diskette überhaupt gemountet
ist wird versucht diese unzumounten. Auf die Besonderheit
mit der Anzeige des Exitcodes kommen wir später zurück.
Und zum Schluß noch etwas, was der geneigte Admin nicht so gerne
sieht - wir aber hier benötigen - ein Eintrag in $HOME/.rhosts
von gustav.
# this is the file .rhosts in $HOME from gustav on foo
# ATTENTION! Set the permissions to 600 for this file!
bar gustav
bar.mynet.org gustav
Damit ermöglichen wir gustav ohne weitere Paßworteingabe das
rlogin (und andere r-Kommandos) von bar auf foo.
Das war schon Alles bei foo.
Zusätzliches an bar
Für den Ort der Scripte gilt das unter "Zusätzliches
an foo" gesagte. Auch auf bar gibt es jeweils ein Script zum Mounten
und eins zum Abmounten. Wenn man sich die Scripte ansieht, findet man immer
wieder ein Konstrukt mit read var - dieses sorgt dafür, daß
das Script auf eine Usereingabe wartet. Damit wird verhindert, daß
das Script einfach durchläuft und der User somit keine Möglichkeit
zum Lesen der Ausgabe hätte. Das ist besonders dann ärgerlich,
wenn das Script über ein Icon gestartet wird - im Fehlerfall würde
das XTerm einfach zugehen, da das Script beendet ist/wird.
Zuerst das Script zum Mounten - floppy_remote_mount.sh.
#!/bin/sh
FLOPPY_HOST=foo
REMOTE_MOUNT_CMD="~/bin/floppy_local_mount.sh"
LOCAL_MOUNT_POINT=/mnt/remote_floppy
ping -qc1 -w1 $FLOPPY_HOST &>/dev/null
EXIT_CODE=$?
if [ $EXIT_CODE != 0 ] ; then
printf "\n\tFehler!"
printf "\n\tVermutl. ist der andere Rechner ($FLOPPY_HOST) nicht eingeschaltet!\n\n"
printf "\n\tWeiter mit <ENTER>!\n\n"
read var
exit $EXIT_CODE
fi
mount -t nfs | grep -i $LOCAL_MOUNT_POINT &>/dev/null
EXIT_CODE=$?
if [ $EXIT_CODE == 0 ] ; then
printf "\n\tFehler!"
printf "\n\tDie Diskette ist bereits über das Netz gemountet!\n\n"
printf "\n\tWeiter mit <ENTER>!\n\n"
read var
exit $EXIT_CODE
fi
R_EXIT_CODE=`rsh $FLOPPY_HOST "$REMOTE_MOUNT_CMD"`
if [ $R_EXIT_CODE != 0 ] ; then
printf "\n\tFehler!"
printf "\n\tVermutl. ist keine Diskette im anderen Rechner ($FLOPPY_HOST) vorhanden!\n\n"
printf "\n\tWeiter mit <ENTER>!\n\n"
read var
exit $R_EXIT_CODE
fi
mount $LOCAL_MOUNT_POINT &>/dev/null
EXIT_CODE=$?
if [ $EXIT_CODE != 0 ] ; then
printf "\n\tFehler!"
printf "\n\tKonnte Floppy nicht übers Netz von ($FLOPPY_HOST) mounten!\n\n"
printf "\n\tWeiter mit <ENTER>!\n\n"
read var
exit $EXIT_CODE
else
printf "\n\tAlles i.O.!\n\tViel Spaß beim Arbeiten!\n\n"
printf "\tDie Diskette steht unter $LOCAL_MOUNT_POINT zur Verfügung.\n"
printf "\n\tEs befinden sich die folgenden Daten auf der Diskette:\n\n"
ls $LOCAL_MOUNT_POINT
fi
printf "\nBeenden mit <ENTER> ...\n"
read var
exit $EXIT_CODE
Was das Script im Einzelnen tut ist eigentlich ersichtlich:
-
ist foo per ping erreichbar
-
versuche an foo die Diskette lokal zu mounten (per rsh wird das Script
floppy_local_mount.sh auf foo aufgerufen)
-
wenn das funktioniert hat wird versucht das Ganze per NFS zu mounten
-
Fertig!
Und dann noch das 2. Script - zum Abmounten: floppy_remote_umount.sh.
#!/bin/sh
FLOPPY_HOST=foo
REMOTE_UMOUNT_CMD="~/bin/floppy_local_umount.sh"
LOCAL_MOUNT_POINT=/mnt/remote_floppy
mount -t nfs | grep -i $LOCAL_MOUNT_POINT &>/dev/null
EXIT_CODE=$?
if [ $EXIT_CODE != 0 ] ; then
printf "\n\tFehler!"
printf "\n\tDie Diskette ist nicht über das Netz gemountet!\n\n"
printf "\n\tWeiter mit <ENTER>!\n\n"
read var
else
umount $LOCAL_MOUNT_POINT &>/dev/null
EXIT_CODE=$?
if [ $EXIT_CODE != 0 ] ; then
printf "\n\tFehler!"
printf "\n\tDie Diskette konnte übers Netz nicht ungemountet werden!\n\n"
printf "\n\tWeiter mit <ENTER>!\n\n"
read var
fi
fi
ping -qc1 -w1 $FLOPPY_HOST &>/dev/null
EXIT_CODE=$?
if [ $EXIT_CODE != 0 ] ; then
printf "\n\tFehler!"
printf "\n\tVermutl. ist der andere Rechner ($FLOPPY_HOST) nicht eingeschaltet!\n\n"
printf "\n\tWeiter mit <ENTER>!\n\n"
read var
exit $EXIT_CODE
fi
R_EXIT_CODE=`rsh $FLOPPY_HOST "$REMOTE_UMOUNT_CMD"`
case "$R_EXIT_CODE" in
0) printf "\n\tAlles i.O.!"
printf "\n\tDie Diskette kann an $FLOPPY_HOST entnommen werden!\n\n"
;;
1) printf "\n\tDiskette war nicht gemountet!"
printf "\n\tDie Diskette kann an $FLOPPY_HOST entnommen werden!\n\n"
;;
*) printf "\n\tFehler!\n\tUnmount der Diskette fehlgeschlagen!\n\n"
;;
esac
printf "\n\tWeiter mit <ENTER>!\n\n"
read var
exit $R_EXIT_CODE
Auch hier ist eigentlich ersichtlich was passiert:
-
ist die Diskette per NFS gemountet
-
wenn ja: dann abmounten
-
wenn nicht: Meldung anzeigen und auf Usereingabe warten - aber das Script
nicht beenden!
-
ist foo per ping erreichbar
-
wenn foo erreichbar führe dort per rsh das Kommando zum Abmounten
der Diskette aus
-
Fertig
Die Besonderheit an den Scripten
Jedes Script startet von bar eine Remoteshell an foo per rsh. Jetzt möchte
man aber an bar den Exitstatus des entfernt ausgeführten Kommandos
haben. Der Exitstatus von rsh-Aufrufen ist aber ebend nur der Exitstatus
des rsh und nicht des entfernt ausgeführten Kommandos. Z.B.: Die rsh
von bar zu foo ist i.O. - aber das mitgegebenen Kommando ist nicht erfolgreich
ausführbar gewesen - dann ist der Exitcode von rsh aber trotzdem 0
(was ja auch logisch ist, denn die Remoteshell konnte ja gestartet werden).
Um nun aber das Ergebnis des Kommandos rauszubekommen, gibt das entfernt
ausgeführte Kommando seinen Exitstatus per Echo einfach auf STDOUT
aus. Auf unserem Rechner wiederum speichern wir diese Ausgabe in einer
Variablen. Und schon haben wir den Exitcode des entfernten Kommandos. Und
an dieser Stelle habe ich an den Scripten etwas geschlumpert - normalerweise
sollte man erst den Exitcode der rsh auswerten und dann den des entfernt
auszuführenden Kommandos. Warum hab´ ich das nicht gemacht?
Ganz einfach: Ich war zu faul! Aber es kommt hinzu, daß das Problem
dann auch wieder nicht so einfach zu lösen ist, da man nicht einfach
alles mit &> umleiten kann. Aber die Lösung
des Problems steht unten.
Das oben Beschriebene kann man einfach ausprobieren, wenn man an seinem
localhost dafür gesorgt hat, daß man auf sich selbst wieder
mit r-Kommandos zugreifen kann (per ~/.rhost). Dann
macht man als normaler User (nicht root) Folgendes:
paul@foo> rsh localhost "/sbin/reboot"
reboot: must be superuser.
paul@foo> echo $?
0
paul@foo> /sbin/reboot
reboot: must be superuser.
paul@foo> echo $?
1
paul@ foo>
Wie unschwer zu erkennen ist, wurde der reboot jedesmal aus dem
selben Grund verweigert - aber der Exitcode ist unterschiedlich! Beim ersten
Mal ist er 0, da ja die rsh erfolgreich ausgeführt werden konnte.
Man bekommt also gar nichts davon mit, daß das Kommando am anderen
Rechner fehlgeschlagen ist. Und wie das umgangen wird, hast Du ebend gerade
erfahren.
Und zum Schluß noch der Weg, den
man beschreiten muß, wenn man die Fehlerausgaben von rsh (z.B. no
route to host) umleiten kann und trotzdem die Ausgabe des Exitcodes der
rsh und des entfernten Kommandos erhält:
paul@foo> R_EXIT_CODE=`rsh localhost '/sbin/reboot &> /dev/null; echo $?' 2>/dev/null`
paul@foo> echo $?
0
paul@foo> echo $R_EXIT_CODE
1
paul@foo> R_EXIT_CODE=`rsh einhostwoichnichtsdarf '/sbin/reboot &> /dev/null; echo $?' 2>/dev/null`
paul@foo> echo $?
1
paul@foo> echo $R_EXIT_CODE
paul@foo>
Wie man sieht bekommt man jetzt den Exitcode für rsh mit dem üblichen
$?
heraus und für das entfernte Kommando in $R_EXIT_CODE. Die
Variable R_EXIT_CODE braucht man aber schon garnicht mehr auswerten,
wenn $? einen Wert <> 0 hat (zumal sie so oder so dann leer
ist!).
Download der Scripte
Wie es sich für eine ordentliche Webseite gehört, sind die Scripte
natürlich alle per Download als tgz
zu erhalten. Nach dem Auspacken mit
tar xvzf nfs_diskette.tgz
stehen sie in einem separatem Directory namens nfs_diskette zur
Verfügung.
So das war Alles! Viel Spaß!
Questions, ideas, comments please mail me at: linux@dev-thomynet.de
Fragen, Ideen, Kommentare bitte per Email an: linux@dev-thomynet.de