NSLU 2 als File-, Mail- und Printserver

Hardware

Die NSLU 2 (aka Slug) ist ein beliebter NAS-Server von Lynksys, ausgestattet mit einem 266MHz-Prozessor, 32MB RAM und 2 USB-Ports. Als Betriebssystem werkelt ein sehr spartanisch ausgestattetes Linux vor sich hin. Dieses kann glücklicherweise durch ein anderes Linux ersetzt werden, was die Möglichkeiten des Einsatzes der NSLU 2 um ein vielfaches erweitert. Es gibt sogar im Netz eine eigene Projektseite für das Modifizieren der NSLU 2. Als Speicher für das Betriebssystem kommt bei mir eine 32GB CF-Karte zum Einsatz, da die Haltbarkeit von USB-Sticks doch begrenzt ist. CF-Karten haben da doch die höhere Lebensdauer. Der Kartenleser hängt am ersten USB-Anschluß. Beim Kartenleser sollte zwingend darauf geachtet werden, das der CF-Schacht von Linux als erstes Gerät erkannt wird. Besser ihr verwendet gleich einen Kartenleser der ausschließlich mit CF-Karten umgehen kann. Am 2.USB-Port hängt über einen USB-Hub der USB-Drucker, eine über USB schaltbare Steckdosenleiste, eine USB-Festplatte und eine Webcam.

Betriebssystem

Die Entscheidung fiel aus Traditionsgründen auf Debian mittlerweile in der Version 7 herausgekommen. Anleitungen, wie ihr die NSLU 2 dafür einrichtet finden sich zu Hauf im Netz. Ich habe die Firmware von einem laufenden Debian im Netzwerk aus mittels des Tools unslug2 geflasht. Das Flashen der Firmware geht ziemlich zügig. Für die eigentliche Installation des Debian-Systems solltet ihr aber auf Grund der geringen Prozessorleistung und dem wenigen RAM 2 bis 3 Stunden einplanen. Der Installer läuft bis auf wenige Abfragen eigenständig durch. Die eigentliche Arbeit beginnt also, wenn der Installationsvorgang abgeschlossen ist.

An Nacharbeiten waren noch zu erledigen:

Setzen des Host-und Domainnamens

hostname slug
sed -e 's/foobar/slug/g' -e '/s/example.org/curt.net/' /etc/hosts > /etc/hosts.new && mv /etc/hosts.new /etc/hosts

die Paket-Repositorys anpassen

echo "deb ftp://ftp.debian-multimedia.org lenny main" >> /etc/apt/sources.list
aptitude update

Dabei kommt es zu einer Warnung, daß der öffentliche Schlüssel von debian-multimedia.org nicht bekannt ist. Also besorgen wir uns diesen Schlüssel und machen ihn bekannt.

gpg --keyserver subkeys.pgp.net --recv-keys 1F41B907
gpg --armor --export 1F41B907 | apt-key add -
aptitude update

Update des gesamten Systems machen

aptitude -fr dist-upgrade

Installieren von ntpdate und einrichten eines cronjobs zum Abgleichen der Systemzeit

aptitude install ntpdate
echo "00 11 * * 1 root ntpdate ptbtime1.ptb.de" >> /etc/crontab

Als Augenschmauß hab ich noch die Datei /etc/mod.tail geändert, so das beim Einloggen eine hübsche Bergrüßung angezeigt wird.

File-Server

Als Fileserver sollte die NSLU 2 folgende Aufgaben bei mir übernehmen:

  1. Bereitstellen von Speicherplatz für Linux-Clients auf der Basis von NFS
  2. Bereitstellen von Speicherplatz für Windows-Clients auf der Basis von SMB
  3. Abruf von Dateien auch von außerhalb des eigenen Netzwerkes über FTP
  4. Zugriff auf Linux-Rechner im lokalen Netzwerk über SSH wobei die NSLU 2 nur als Vermittler auftritt

Zugriff auf Linux-Rechner im lokalen Netzwerk

Der Zugriff auf die Linux-Rechner im lokalen Netzwerk zu Wartungszwecken oder um mal doch eben eine dringend benötigte Datei zu holen geschieht über ssh bzw. scp. Sollten die betreffenden Rechner down sein, hilft etherwake um sie mal eben hochzufahren.

Printserver

Zuerst muß einmal der Drucker eingerichtet werden. Dazu habe ich das cups-Webinterface benutzt. Vorher muß natürlich die Konfigurationsdatei /etc/cups/cupsd.conf so eingerichtet sein, das cups auch im gesamten Netzwerk lauscht und die Zugriffsrechte angepaßt sind.

  1. Listen localhost:631 ändern in Listen *:631
  2. BrowseAllow All ändern in BrowseAllow @LOCAL
  3. Im Abschnitt Restrict Access to the Server wird die Zeile
  4. Allow from 192.168.1.*
  5. eingefügt und in den Abschnitten Restrict access to the admin pages
  6. und Restrict access to configuration files habe ich die Zeilen
  7. Allow 192.168.1.110
  8. für die IP meines Desktop-Rechners ans Ende gestellt.

Danach muß der cups-Daemon neu gestartet werden.

/etc/init.d/cups restart

Der Drucker war dann mittels des Webinterfaces schnell eingerichtet.

Auf zwei mögliche Hürden sei noch hingewiesen:

Unter Umständen bekommt ihr beim Versuch den angezeigten Drucker einzurichten die Seite mit der Fehlermeldung Error 426 Upgrade Required angezeigt und werdet ein paar Sekunden später auf https://SERVER:631/admin weitergeleitet, die aber nicht erreichbar ist. Die Fehlermeldung ist etwas irreführend. Der eigentliche Knackpunkt ist das fehlende Zertifikat für die Authentifizierung des Servers. Mit

openssl req -new -x509 -keyout /etc/cups/ssl/server.key -out /etc/cups/ssl/server.crt -days 365 -nodes

könnt ihr euch ein Zertifikat erstellen. Dann klappt auch die Authentifizierung.

Auf keinen Fall solltet ihr der Versuchung unterliegen auf "Testseite drucken" zu klicken. Die Folge wird sein, daß das Webinterface ständig am Laden ist und auch die ssh-Sitzung blockiert. Als Testseite im Webinterface wird die Druckerbeschreibungsdatei *.ppd verwendet. Die kann schon mal etliche Seiten betragen, die von einem 266MHz-Prozessor und 32MB Arbeitsspeicher zum Drucken aufgearbeitet werden müssen. Das dauert eben. Ihr druckt ja lokal auf der NSLU 2 und nicht von einem Rechner im Netzwerk aus, auch wenn das auf den ersten Blick so aussieht. Ein Versuch, die Datei /etc/fstab auf dem lokalen System mittels lp zu drucken, verdeutlicht das. In einer 2.Konsole könnt ihr euch top anzeigen lassen und die Ausgabe bestätigt: zum Umsetzen der Druckdaten der kleinen fstab braucht die NSLU 2 gut 2 Minuten.

Einrichten der Drucker-Clients

Da das Redmonder Betriebssystem zum Drucken auch cups-Server ansprechen kann, ist die Einrichtung relativ einfach. Einen Netzwerkdrucker mit der URL http://SERVER:631 einrichten, den zugehörigen Treiber des Druckermodells auswählen und schon steht dem Drucken nichts entgegen.

Bei den Linux-Clients ist es ebenso völlig unproblematisch. Mit dem Tool zum Einrichten eines Drucker fügt ihr einen neuen Drucker vom Typ IPP-Drucker hinzu, als URI gibt man ipp://SERVER:631/printers/Druckername an und wählt den richtigen Treiber aus.

Energie sparen

Jetzt ist natürlich ein Drucker, der 24/7 am Netz hängt, nicht gerade energiesparend. Besser wäre es ja, der Drucker ginge nur an, wenn ein Druckauftrag ansteht und schaltet sich nach erfolgtem Ausdruck wieder ab. Aber dazu haben wir ja unsere Netzleiste mit USB-Anschluß. Die Software zum Steuern der Netzleiste enthält das Paket sispmctl. Aber woher soll das Programm die Information bekommen, wann es welchen Schaltvorgang auslösen soll? Vor Jahren hatte ich schon mal auf einen Linux-Server einen PDF-Drucker über Samba im Netzwerk freigegeben. Dabei war die Befehlszeile für den PDF-Drucker nichts anderes als der Aufruf eines Scriptes. Man müßte also nur die zu druckenden Daten durch ein Script leiten, welches die Netzleiste schaltet und dann die Druckdaten an des entsprechende Backend weiterleitet.

Bevor wir aber zum eigentlichen Script kommen, müssen wir uns über ein Rechteproblem klar werden. Der Druckvorgang wird als User lp gestartet. Dieser hat aber keinen schreibenden Zugriff auf die Eigenschaften von USB-Geräten, wie sie durch sispmctl vorgenommen werden. Wir müssen also dafür sorgen, das sispmctl durch Mitglieder der Gruppe lp mit den Privilegien von Root ausgeführt wird. Dazu habe ich gemeinsam mit Stefan Lütje mehrere Möglichkeiten durchgearbeitet.

1.Variante: Wir ändern die Gruppe auf lp und setzen das Sticky-Bit:

chgrp lp /usr/bin/sispmctl
chmod u+s /usr/bin/sispmctl

2.Variante: Wir erstellen eine udev-Regel, die das USB-Device der Gruppe sispm zuordnet und erlauben damit allen Gruppenmitgliedern das Schalten der Steckdosen.

groupadd -g 111 sispm
adduser lp sispm
touch /etc/udev/sispm.rules
echo -e "SYSFS{idVendor}==\"04b4\", SYSFS{idProduct}==\"fd13\", MODE=\"0660\", GROUP=\"sispm\"" >> /etc/udev/sispm.rules
ln -s /etc/udev/sispm.rules /etc/udev/rules.d/90-sispm.rules 

Die Variante sieht auf den ersten Blick sehr schlüssig aus. Leider ist der User lp während des Druckvorganges aus irgendwelchen Gründen nicht Mitglied der Gruppe sispm. Sollte irgendjemand dem Problem auf die Schliche kommen, sind wir für jede Idee dankbar.

3.Variante: Wir machen einen Eintrag in der Datei /etc/sudoers, der dem User lp das Ausführen von sispmctl erlaubt.

lp	ALL=(root)NOPASSWD: /usr/bin/sispmctl -q -o 1

Im Script haben wir uns für die dritte Variante entschieden.

#!/bin/bash
#
#Beschreibung: schaltet den Drucker an und druckt das Dokument aus
#
#benoetigt: /usr/bin/sispmctl
#
#Aufruf: printeron.sh Printer Printerport
###################################################################
#Variablen
retval=0
usbls="Hewlett-Packard deskjet 980c"
printerdevice="hp:/usb/DeskJet_980C?serial=MY11F1C1H0OF"
plugnumber=1		#Nummer der zu schaltenden Dose
#Prüfe auf Voraussetzungen
if [[ ! -e /usr/bin/sispmctl ]] || [[ ${#} == 0 ]]; then
	retval=1
fi
if [[ ${retval} == 0 ]]; then
	sudo /usr/bin/sispmctl -q -o ${plugnumber}
	retval=${?}
	if [[ ${retval} == 0 ]]; then
		#warte bis Drucker bereit
		until [[ $(lsusb | grep "${usbls}") ]]
		do
			sleep 1
		done
		#Drucke
		export DEVICE_URI=${printerdevice}
		exec -a "${DEVICE_URI}" /usr/lib/cups/backend/hp "${@}"
	fi
fi
exit ${retval}

Das Script speichern wir im Verzeichnis /usr/lib/cups/backend/ und machen es ausführbar.

Jetzt muß nur noch der Druckauftrag an das Script weitergeleitet werden. Dazu tragen wir in der Datei /etc/cups/printers.conf als DeviceURI den Namen des Scripts ein.

Zum Abschalten könnte man das Spool-Verzeichnis überwachen und beim Leeren des Verzeichnisses die Leiste auf Off schalten. Im Verzeichnis /var/spool/cups/ wird während des Druckvorganges eine Datei nach dem Muster d0001.001 angelegt und nach Beendigung des Druckvorganges wieder entfernt. Wir sorgen also dafür, daß der Drucker erst dann abgeschaltet wird, wenn sich keine solche Datei mehr im Spool-Verzeichnis befindet. Wir lassen also das Verzeichnis /var/spool/cups/ von iwatch auf das Löschen von Dateien überwachen und führen dann das Script printeroff.sh aus. Die Konfigurationsdatei von iwatch sieht folgendermaßen aus:

<?xml version="1.0" ?>
<!DOCTYPE config SYSTEM "/etc/iwatch/iwatch.dtd" >
<config>
  <guard email="root@localhost" name="IWatch"/>
  <watchlist>
    <title>Printer set to off</title>
    <contactpoint email="root@localhost" name="Administrator"></contactpoint>
    <path type="single" events="delete" filter="d*-00*" exec="printeroff.sh">/var/spool/cups</path>
  </watchlist>
</config>

Das Script überprüft lediglich noch, ob das Verzeichnis tatsächlich leer ist und schaltet dann den Drucker ab. Das Sleep sorgt dafür, daß der Drucker auch eventuelle Reinigungsvorgänge noch erledigt, bevor er abgeschaltet wird.

#!/bin/bash
#
#Beschreibung: schaltet den Drucker aus wenn Spooler leer ist
#
#benoetigt: /usr/bin/sispmctl
#
#Aufruf: printeroff.sh
##############################################################
retval=0
plugnumber=1	#Nummer der zu schaltenden Dose 
#Warte ob Drucker nicht noch Restarbeiten erledigt
sleep 20
if [[ -e /usr/bin/sispmctl ]];then
	retval=1
fi
ls --ignore=tmp /var/spool/cups/
retval=${?}
if [[ ${retval} == 0 ]] && [[ ! $(ls --ignore=tmp /var/spool/cups/) ]]; then	
	sispmctl -q -f ${plugnumber}
	retval=${?}
fi
exit ${retval}

Es kann sein, daß sich im Spool-Verzeichnis noch jede Menge Dateien in der Art von c00597 befinden. Dabei handelt es sich um Dateien, die durch die History-Funktion von cups angelegt werden, die alle fertigen Druckjobs noch mal abspeichert. Diese Funktion ist per default auf ON gestellt. Das Script läuft dann natürlich ins Leere und der Strom wird nicht abgeschaltet. Wenn Du auf die History-Dateien nicht verzichten willst, mußt Du die ls-Aufrufe im Script um ein weiteres ignore ergänzen:

ls --ignore=tmp --ignore=c0* /var/spool/cups/

Brauchst Du dagegen die Funktion nicht, kannst Du die Dateien bedenkenlos löschen und schaltest die Funktion in der Datei /etc/cups/cupsd.conf einfach ab:

PreserveJobHistory Off

Off oder No - in meiner cupsd.conf steht No, in der Hilfe zu cups steht Off - vielleicht funktioniert beides.

Eine mögliche Stolperfalle soll hier nicht verschwiegen werden. Wenn die Zeit hinter sleep zu groß ist, kann es passieren, daß nach dem Abschicken mehrerer Druckaufträge der Drucker vom zuerst aufgerufenen printeroff-Script abgeschaltet wird. Das hat zwar keine Auswirkung auf die Ausführung der Druckjobs, aber die dem Drucker zu eventuellen Reinigungszwecken zur Verfügung gestellte Zeit nach dem letzten Druckauftrag stimmt dann nicht mehr. Stefan erstellt mit jedem printeron-Script eine temporäre Datei /var/run/cups/sispm/jobdone. Im printeroff-Script vergleicht er dann den Zeitstempel der erstellten Datei mit der eingestellten Sleep-Zeit. Somit umgeht er das Problem.

#!/bin/bash
#
#Beschreibung: schaltet den Drucker aus wenn Spooler leer ist
#
#benoetigt: /usr/bin/sispmctl
#
#Aufruf: printeroff.sh
##############################################################
retval=0
plugnumber=1	#Nummer der zu schaltenden Dose 
waittime=600	#Zeit für Restarbeiten
#Warte ob Drucker nicht noch Restarbeiten erledigt
sleep ${waittime}
if [[ -e /usr/bin/sispmctl ]];then
	retval=1
fi
ls --ignore=tmp /var/spool/cups/
retval=${?}
stamptime=$(/usr/bin/stat -c %Z "/var/run/cups/sispm/jobdone")
unixtime=$(date +%s)
difference=$(( $unixtime - $stamptime ))
if [[ ${difference} -ge ${waittime} ]]; then
	if [[ ${retval} == 0 ]] && [[ ! $(ls --ignore=tmp /var/spool/cups/) ]]; then	
		sispmctl -q -f ${plugnumber}
		retval=${?}
	fi
fi
exit ${retval}

Eine ähnliche Lösung beschreibt auch Jörg Jaspert in seinem Blog. Er bemüht zum Abschalten des Druckers allerdings einen cron-Job. Mehrere Wege führen eben zum Ziel.

Wer keine Lust zum Abtippen hat, findet die Scripte und die iwatch-Datei hier.

Energie sparen - neue Variante

Seit dem letzen Update von cups funktioniert das direkte Ansteuern des usb-Backends über das Script nicht mehr. Deshalb mußte eine neue Lösung her. Nach wie vor wird von iwatch das Verzeichnis /var/spool/cups überwacht. Allerdings jetzt auf das Erstellen von Dateien, also das Eintreffen eines Druckjobs. Ist das der Fall, wird das neue Script printeron.sh ausgeführt. Diese prüft zuerst den Status der zu schaltenden Leiste. Ist diese bereits eingeschaltet, beendet sich das Script. Andernfalls wird der Strom eingeschaltet und solange gewartet, bis das Verzeichnis /var/spool/cups leer ist. Nach 40 Sekunden für Restarbeiten des Druckers wird der Strom wieder abgeschaltet. Das neue Script und die Konfigurationsdatei für iwatch stehen hier zum Download bereit.