mount.local für wechselnde (FTP-)USB-Platten

Gero013

Neuer User
Mitglied seit
5 Mai 2010
Beiträge
190
Punkte für Reaktionen
0
Punkte
0
Hallo,

wer (wie ich) öfters mal die USB-Platte wechselt, bzw. mehrere an einem Hub wechselnd an- und ausschaltet, dem hilft das mounten der usb-Platten nach uStor## herzlich wenig (weil sich die Zahl ändert, bzw. unterschiedliche Medien die gleiche Zahl erhalten).

Der autorun/autoend Mechanismus ist dagegen so genial, dass er sich leicht verwenden lässt, um Platten zu ihrer UUID zu mounten, auch wenn diese (im Vorfeld) garnicht bekannt ist.

Für die FTP-Benutzer habe ich folgenden Zugriff umgesetzt:
Alle Verzeichnisse der ersten Ebene der Festplatte können individuell erlaubt werden.
Alle FTP-Benutzer haben unter /home ein persönliches Verzeichnis.
Beim Einschalten der Platte werden die Verzeichnisse, für die der Benutzer zugelassen ist unter seinem home-Verzeichnis angelegt und anschließend wird das entsprechende Verzeichnis der FTP-Platte dort eingebunden.
Schreib- und Leseberechtigung können über die Verzeichnisrechte eingestellt werden. Verzeichnisse, die mehreren Benutzern zugeordnet werden sollten das Sticky-Bit erhalten.
In der Benutzer-VW fürs WebIF kann bei einem neuen Benutzer jedes Verzeichnis per Mausklick zugeordnet werden.

Dazu hilft folgende autorun.sh im Wurzelverzeichnis der Platte
Code:
#!/bin/sh
mp=$(dirname $0)
dev=$(mount | grep $mp)
dev=${dev%% *}
tmp=$(/usr/sbin/blkid -s UUID $dev)
tmp=${tmp##*=\"}
tmp=${tmp%%\"*}
logger autorun "dev [$dev] has uuid [$tmp]"
mkdir -p /var/media/$tmp
mount $mp /var/media/$tmp -o bind
[ -x $mp/rc.local ] && source rc.local start /var/media/$tmp

In rc.local (auch im Wurzelverzeichnis der Platte) lassen sich jetzt Verzeichnisse ins lokale Filesystem mounten, indem man den übergebenen Pfad verwendet.
Das (für mich) angenehme ist, dass der Mechanismus auch noch nach dem Klonen der Platte (jetzt mit neuer UUID) weiter funktioniert.

Fehlt noch die autoend.sh
Code:
#!/bin/sh
mp=$(dirname $0)
dev=$(mount | grep $mp)
dev=${dev%% *}
tmp=$(/usr/sbin/blkid -s UUID $dev)
tmp=${tmp##*=\"}
tmp=${tmp%%\"*}
logger autoend "dev [$dev] has uuid [$tmp]"
[ -x $mp/rc.local ] && source rc.local stop /var/media/$tmp
umount /var/media/$tmp
rmdir /var/media/$tmp

Hier (m)eine rc.local:
//update:
rc.local derart geändert, dass Benutzer und deren FTP-Verzeichnisse aus einer separaten Datei eingelesen werden, die auch im Wurzelverzeichnis der einzubindenen Platte liegt.
//2. update:
rc.local wurde um Benutzer-VW erweitert
Code:
#!/bin/sh
myself=$0
mode=$1
base=$2
fusers="$base/ftpusers.local"

verify_user() {
local user=$1
local pentry=$2
local sentry=$3
logger "$myself: verify user [$user]"
grep -l $user /etc/passwd || echo "$pentry" >> /etc/passwd
grep -l $user /etc/shadow || echo "$sentry" >> /etc/shadow
mkdir -p /home/$user 2>/dev/null
chown $user:ftpuser /home/$user
}

attach_dir() {
local user=$1
local dir=$2
mkdir -p /home/$user/$dir
mount $base/$dir /home/$user/$dir -o bind
}

detach_dir() {
local user=$1
local dir=$2
umount /home/$user/$dir
}

processUsers() {
local IFS=';'   
cat $fusers | while read user pentry sentry rest; do
   [ "x$mode" = "xstart" ] && verify_user $user $pentry $sentry
   for dir in $rest; do
      if [ "x$mode" = "xstart" ]; then
         attach_dir $user $dir
      else
         detach_dir $user $dir
      fi
   done
done   
}

createUserPage() {
local base=$1   
local fusers="$base/ftpusers.local"
local dirlist=$(ls -l $base | grep "^d" | grep -Ev "log|lost|System" | awk '{ print $9; }')
echo -n '<div id="userlist" class="chapter"><div class="title">'
echo -n 'Liste der FTP-Benutzer'
echo -n '</div><br/><br/><table><tr valign="top"><td class="title">'
echo -n 'Benutzer'
echo -n '</td><td class="title">'
echo -n 'Verzeichnisse'
echo -n '</td></tr>'
local IFS=';'   
local uid=1001 gid=100
cat $fusers | while read user pentry sentry rest; do
   echo -n "<tr valign=\"top\"><td class=\"data\">$user</td><td class=\"data\">"
   IFS=':'
   set -- $pentry
   uid=$3
   gid=$4
   for dir in $rest; do
       echo "$dir<br/>"
   done
   IFS=';'
   echo -n "</td></tr>"
done
unset IFS
let uid="uid+1"
echo -n '<tr><td colspan="2" class="title">'
echo -n 'neuer Benutzer:'
echo -n '</td></tr><tr valign="top"><td><table><tr><td>'
echo -n 'Name:'
echo -n '</td><td><input type="text" name="new_ftp_user" size="20" maxlength="30"/></td></tr><tr><td>'
echo -n 'Kennwort:'
echo -n '</td><td><input type="text" name="new_ftp_pass" size="20" maxlength="30"/></td></tr></table></td><td>'
echo -n '<input type="hidden" name="new_ftp_uid" value="'$uid'"/>'
echo -n '<input type="hidden" name="new_ftp_gid" value="'$gid'"/>'
local n=0
for dir in $dirlist; do
   echo "<input type=\"checkbox\" name=\"ftpdir$n\" value=\"$dir\"/>$dir<br/>"
   let n="$n+1"   
done
echo -n '</td></tr><tr><td>&nbsp;</td><td><input type="submit" value="Anlegen"/></td></tr>'
echo '</table></div>'
}

addUser() {
local ftpuser=$(echo "$FORM_new_ftp_user" | sed 's/\([a-z_0-9]*\).*/\1/')
local ftppass=$(echo "$FORM_new_ftp_pass" | sed 's/\([a-z_0-9]*\).*/\1/')
local ftpuid=$(echo "$FORM_new_ftp_uid" | sed 's/\([0-9]*\).*/\1/')
local ftpgid=$(echo "$FORM_new_ftp_gid" | sed 's/\([0-9]*\).*/\1/')
local allowed=${FORM_new_ftpdirs}
local dirlist=$(ls -l $base | grep "^d" | grep -Ev "log|lost|System" | awk '{ print $9; }')
local ftpdirlist=''
for n in $(seq 0 99); do
   if [ ! -z "$FORM_ftpdir$n" ]; then
      ftpdirlist="$ftpdirlist $FORM_ftpdir$n"
   fi
done
if [ -z $user ] || [ -z $pass ] || [ -z $ftpuid ] || [ -z $ftpgid ]; then return; fi
if [ $ftpuid -lt 1000 ] then let ftpuid="ftpuid+1000"; fi
grep "$ftpgid" /etc/group 
if [ $? = 1 ]; then   
   ftpgid=$(grep users /etc/group)   
   ftpgid=${ftpgid#users:x:}
   ftpgid=${ftpgid%:.*}
fi
local pass=$(mkpasswd -m md5 $ftppass)
local entry="$user"
entry="$entry;$user:x:$ftpuid:$ftpgid:ftp user,,,:/home/$user:/bin/sh"
entry="$entry;$user:$pass:14789:0:99999:7:::"
for dir in $dirlist; do
   echo $ftpdirlist | grep $dir && entry="$entry;$dir"
done   
echo $entry
}

logger "rc.local: 0[$myself] 1[$mode] 2[$base]"
case $mode in
start)
addgroup -g 139 ftpuser 2>/dev/null
[ -s $fusers -a -r $fusers ] && processUsers
;;
stop)
[ -s $fusers -a -r $fusers ] && processUsers
;;
manage)
createUserPage $(dirname $0)
;;
adduser)
addUser
;;
*) logger error "[$myself]: invalid mode! only start/stop supported, [$mode] given!"
;;
esac

Die Datei der FTP-Benutzer sieht wie folgt aus (pro Benutzer eine Zeile):
Code:
userA;userA:x:1001:139:public ftp user,,,:/home/userA:/bin/sh;userA:$a$very$secret$password:14772:0:99999:7:::;public
Trennzeichen der Felder einer Zeile ist ';'
Aufbau einer Zeile:
Code:
Benutzer-name
Zeile für den Benutzer in /etc/passwd
Zeile für den Benutzer in /etc/shadow
Verzeichnis-1 [; ... Verzeichnis-n]

Ok, zumindest in 1.13 wird autoend.sh wohl nicht automatisch beim umount-Befehl ausgeführt, d.h. es fehlt noch ein kleiner Kick. Ich habe mir beholfen, indem ich unter ./root/bin (in der FW-Entwicklungsumgebung) eine Datei "unmount" mit folgendem Inhalt erzeugt habe (selbstverständlich muss diese noch ausführbar gemacht werden):
Code:
#!/bin/sh
dev=$1
if [ -z $dev ]; then
   echo "need a special device to unmount - typically an usb-drive"
   exit 1
elif [ ! -b $dev ] && [ ! -c $dev ]; then
   echo "need a special device to unmount - typically an usb-drive"
   exit 2
else
   chkdev=$(mount | grep $dev | head -n 1 | awk '{ print $1; }')
   if [ $dev != $chkdev ]; then
      echo "special dev [$dev] not mounted"
      exit 3
   fi
   mp=$(mount | grep $dev | head -n 1 | awk '{ print $3; }')
   logger unmount "should umount device [$dev] from [$mp]"
   [ -x $mp/autoend.sh ] && $mp/autoend.sh
   umount $mp
   exit 0
fi

Damit wird die Platte duch einschalten eingebunden und kann via webIF oder einem "unmount /dev/sda1" wieder freigegeben und anschließend ausgeschaltet werden.

Vielleicht kann's ja der eine oder andere brauchen.

Gruß Gero
 
Zuletzt bearbeitet:
Damit mountest du deine Platte mit der UUID als Namen?

Im trunk gibts die Möglichkeit mit Freetzmount die Platten mit dem Label als Mountpoint zu mounten.

MfG Oliver
 
Damit mountest du deine Platte mit der UUID als Namen?
Vielleicht geht's einfacher und/oder eleganter - da habe ich kein Problem mit.
Für mich tut es das obige Script.
Der Vorteil für mich: ich kann es auf jede USB-Platte aufspielen und sobald ich die Platte einschalte wird sie so ins FS eingebunden, wie mir das vorschwebt - und das ist für mich das wichtigste.

Jetzt werde ich die (nach Deinem Hinweis auf Wicky) noch um das Anlegen der FTP-Benutzer erweitern und dann dürfte es gut sein ;)

Im trunk gibts die Möglichkeit mit Freetzmount die Platten mit dem Label als Mountpoint zu mounten.
Danke für den Hinweis.

Da bei mir der Erfolg eines trunk-Images vom Wetter, oder der Temperatur der Box abhängt (vielleicht auch von der Laune meiner Nachbarin?) - ich habe nicht die geringste Ahnung - deshalb bleibe ich lieber bei dem, was bei mir funktioniert.
Mit der FW 1.13 kann ich mich beim menuconfig austoben, kann eigene Pakete zufügen und wieder wech schmeißen und das Flaschen klappt einfach immer.
Habe auch schon mit eigenem Kernel und modifizierter Busybox experimentiert - klappt einfach nur.

Leider habe ich nicht mal einen Ansatz zur Fehlersuche, wenn ein Trunk-Image zum reboot-Loop führt - für mich schlimmer als Lottospielen oder von einer Tratschtante das Ohr abgekaut zu bekommen ...

Gruß Gero
 
Zuletzt bearbeitet:
Das Vorgehen beim Trunk ist imho relativ simpel. Man fängt mit der kleinsten Möglichkeit an. Box wählen, make aufrufen, flashen. Mehr nicht. Wenn das läuft: nächstes Paket. Wenn das dann läuft.... Eben bis es mal nicht mehr läuft. Dann spontan das grad eben noch funktionierende Image flashen, und entweder selbst rausfinden, was falsch ist, oder suchen/posten.
Kommst du bei deiner Box denn nicht durcheinander mit der Entwicklung des Webinterfaces? Denn im Trunk haben die Scripte tatsächlich andereMöglichkeiten...
 
Hallo,

das war genau meine Vorgehensweise. So hatte ich einmal erfolgreich ein Trunk-Image geflasht und damit experimentiert.
Als es dann den Brunch für mich gab, dachte ich, ich nehme meine Einstellungen vom Trunk und baue mir damit das Image. Soweit die Theorie.

In der Praxis lief die Box (jeweils ca. 2-3 min) ohne ssh, ohne Freetz-WebIF - nur AVM-Web lief - und in immer kürzeren Abständen fing die Box an zu rebooten. Glücklicherweise funktionierte noch die Verbindung zum Internet, sodass ich noch hier und im Wiki recherchieren und einen Hilferuf posten konnte.
Anschließend versuchte ich ein recover mit dem trunk-image, welches vorher funktioniert hatte - ebenso reboot-Loops.
Erst als ich ein recover mit 1.13 versuchte, ging alles wieder.

Deshalb bin ich jetzt auf der Box auf 1.13 und mounte den Prototypen vom branch via nfs (mit jeweiligem Neustart des Freetz-WebIFs). So bin ich zumindest arbeitsfähig. Für anderweitige Experimente fehlt mir momentan Zeit und Lust.

Gruß Gero
 
So, nachdem ich wieder ein trunk-image am Laufen habe, konnte ich mich dem Vorschlag von herman widmen und eine (Mini-)Benutzer-VW für FTP-Benutzer schnitzen.

erste Erweiterung für rc.local erstellt das Formular fürs WebIF:
Code:
createUserPage() {
local base=$1   
local fusers="$base/ftpusers.local"
local dirlist=$(ls -l $base | grep "^d" | grep -Ev "log|lost|System" | awk '{ print $9; }')
echo -n '<div id="userlist" class="chapter"><div class="title">'
echo -n 'Liste der FTP-Benutzer'
echo -n '</div><br/><br/><table><tr valign="top"><td class="title">'
echo -n 'Benutzer'
echo -n '</td><td class="title">'
echo -n 'Verzeichnisse'
echo -n '</td></tr>'
local IFS=';'   
local uid=1001 gid=100
cat $fusers | while read user pentry sentry rest; do
   echo -n "<tr valign=\"top\"><td class=\"data\">$user</td><td class=\"data\">"
   IFS=':'
   set -- $pentry
   uid=$3
   gid=$4
   for dir in $rest; do
       echo "$dir<br/>"
   done
   IFS=';'
   echo -n "</td></tr>"
done
unset IFS
let uid="uid+1"
echo -n '<tr><td colspan="2" class="title">'
echo -n 'neuer Benutzer:'
echo -n '</td></tr><tr valign="top"><td><table><tr><td>'
echo -n 'Name:'
echo -n '</td><td><input type="text" name="new_ftp_user" size="20" maxlength="30"/></td></tr><tr><td>'
echo -n 'Kennwort:'
echo -n '</td><td><input type="text" name="new_ftp_pass" size="20" maxlength="30"/></td></tr></table></td><td>'
echo -n '<input type="hidden" name="new_ftp_uid" value="'$uid'"/>'
echo -n '<input type="hidden" name="new_ftp_gid" value="'$gid'"/>'
local n=0
for dir in $dirlist; do
   echo "<input type=\"checkbox\" name=\"ftpdir$n\" value=\"$dir\"/>$dir<br/>"
   let n="$n+1"   
done
echo -n '</td></tr><tr><td>&nbsp;</td><td><input type="submit" value="Anlegen"/></td></tr>'
echo '</table></div>'
}
Dabei werden alle Verzeichnisse der ersten Ebene der USB-Platte aufgelistet und können per Checkbox dem (neuen) Benutzer zugeordnet werden. Bestehende Benutzer werden aufgeführt mit den Verzeichnissen auf die sie Zugriff haben (siehe Bild).

Die zweite Erweiterung von rc.local verarbeitet die Daten aus dem Formular und erstellt einen Eintrag für die Benutzer-Datei, die beim Einschalten der Festplatte abgearbeitet wird:
Code:
addUser() {
local ftpuser=$(echo "$FORM_new_ftp_user" | sed 's/\([a-z_0-9]*\).*/\1/')
local ftppass=$(echo "$FORM_new_ftp_pass" | sed 's/\([a-z_0-9]*\).*/\1/')
local ftpuid=$(echo "$FORM_new_ftp_uid" | sed 's/\([0-9]*\).*/\1/')
local ftpgid=$(echo "$FORM_new_ftp_gid" | sed 's/\([0-9]*\).*/\1/')
local allowed=${FORM_new_ftpdirs}
local dirlist=$(ls -l $base | grep "^d" | grep -Ev "log|lost|System" | awk '{ print $9; }')
local ftpdirlist=''
for n in $(seq 0 99); do
   if [ ! -z "$FORM_ftpdir$n" ]; then
      ftpdirlist="$ftpdirlist $FORM_ftpdir$n"
   fi
done
if [ -z $user ] || [ -z $pass ] || [ -z $ftpuid ] || [ -z $ftpgid ]; then return; fi
if [ $ftpuid -lt 1000 ] then let ftpuid="ftpuid+1000"; fi
grep "$ftpgid" /etc/group 
if [ $? = 1 ]; then   
   ftpgid=$(grep users /etc/group)   
   ftpgid=${ftpgid#users:x:}
   ftpgid=${ftpgid%:.*}
fi
local pass=$(mkpasswd -m md5 $ftppass)
local entry="$user"
entry="$entry;$user:x:$ftpuid:$ftpgid:ftp user,,,:/home/$user:/bin/sh"
entry="$entry;$user:$pass:14789:0:99999:7:::"
for dir in $dirlist; do
   echo $ftpdirlist | grep $dir && entry="$entry;$dir"
done   
echo $entry
}

Ich werde es noch in den Prototypen integrieren und die rc.local in eine Lib überführen und dann gibt es ein neues Packerl.

Gruß Gero
 

Anhänge

  • ftp-user.png
    ftp-user.png
    383.2 KB · Aufrufe: 12

Zurzeit aktive Besucher

Statistik des Forums

Themen
246,300
Beiträge
2,249,713
Mitglieder
373,904
Neuestes Mitglied
Elemir
Holen Sie sich 3CX - völlig kostenlos!
Verbinden Sie Ihr Team und Ihre Kunden Telefonie Livechat Videokonferenzen

Gehostet oder selbst-verwaltet. Für bis zu 10 Nutzer dauerhaft kostenlos. Keine Kreditkartendetails erforderlich. Ohne Risiko testen.

3CX
Für diese E-Mail-Adresse besteht bereits ein 3CX-Konto. Sie werden zum Kundenportal weitergeleitet, wo Sie sich anmelden oder Ihr Passwort zurücksetzen können, falls Sie dieses vergessen haben.