Die Minimaleinstellungen für lpd
liefern ein System, das Dateien in
Warteschlangen verwalten und sie drucken kann. Es kümmert sich aber nicht
darum, ob der Drucker die Dateien überhaupt versteht und wird
vermutlich keine ansehnlichen Ausgaben produzieren. Trotzdem ist diese
einfache Konfiguration der erste Schritt, um das System zu verstehen.
Um eine neue Warteschlange zu erzeugen, muß man einen Eintrag in
/etc/printcap
hinzufügen und ein neues Spool-Verzeichnis unter
/var/spool/lpd
erzeugen.
Ein Eintrag in /etc/printcap
sieht etwa so aus:
# lokaler DeskJet 500
lp|dj|deskjet:\
:sd=/var/spool/lpd/dj:\
:mx#0:\
:lp=/dev/lp0:\
:sh:
Dies definiert eine Warteschlange mit den Namen
lp
, dj
und deskjet
, wobei /var/spool/lpd/dj
als Spool-Verzeichnis benutzt wird. Die maximale Größe der Aufträge
ist nicht begrenzt und am Anfang der Druckaufträge wird kein
Deckblatt, z.B. mit dem Namen der Person, die den Druckauftrag
abgeschickt hat, ausgegeben. Der Drucker würde in diesem Beispiel
an /dev/lp0
hängen.
Jetzt wäre der richtige Augenblick, um die printcap Manual Page zu lesen.
Das obige Beispiel sieht sehr einfach aus, hat aber ein Problem. Wenn man nicht Dateien an das Drucksystem übergibt, die ein DeskJet 500 verstehen kann, wird dieser Drucker seltsame Sachen ausgeben. Wenn man z.B. eine gewöhnlichen UNIX-Textdatei an den Deskjet schickt, wird man folgende Ausgabe erhalten:
Zeile eins
Zeile zwei
Zeile drei
Verursacht wird dieser Fehler dadurch, daß Linux einen Zeilenumbruch in einer Textdatei anders kodiert als DOS und Windows, deren Kodierung die meisten Drucker erwarten. Würde eine PostScript-Datei ausgegeben, würde der Drucker einfach die PostScript-Befehle ausdrucken, statt diese zu interpretieren.
Offensichtlich wird mehr benötigt, und genau das ist die Aufgabe
von Filtern. Dem aufmerksamen Leser werden bei der printcap
Manual Page die Spool-Attribute if
und of
aufgefallen
sein. if
, der Inputfilter, ist genau das, was wir jetzt
brauchen.
Um das Problem mit dem Zeilenumbruch beim Drucken von Textdateien
zu lösen, könnte man ein Shellskript mit dem Namen
filter
schreiben, das die Kodierung des Zeilenumbruches
anpaßt. Damit der lpd
dieses Skript aufruft, muß
dem printcap
-Eintrag des Druckers eine if
-Zeile hinzugefügt
werden:
lp|dj|deskjet:\
:sd=/var/spool/lpd/dj:\
:mx#0:\
:lp=/dev/lp0:\
:if=/var/spool/lpd/dj/filter:\
:sh:
Ein einfaches Filterskript könnte sein:
#!perl
# Die obige Zeile muß den kompletten Pfad zu perl
# enthalten. Dieses Skript muß ausführbar sein:
# chmod 755 filter
while(<STDIN>){chop $_; print "$_\r\n";};
# Eventuell möchte man, daß am Ende des Druckauftrages
# ein Seitenvorschub ausgeführt wird. Dieses ist
# insbesondere bei Tintenstrahl- und Laserdruckern
# sinnvoll:
#print "\f";
Würde man das System so konfigurieren, hätte man eine Warteschlange, die wunderbar für UNIX-Textdateien funktionieren würde. Natürlich gibt es vier Millionen bessere Möglichkeiten, diesen Filter zu schreiben, aber wenige sind so anschaulich. Der Leser möge dieses effizienter gestalten.
Das einzige verbleibende Problem besteht darin, daß man heute meistens keine Textdateien drucken möchte. Vielmehr sollen meistens PostScript- oder Grafikdateien ausgegeben werden. Auch dieses Problem läßt sich mit einem Inputfilter lösen. Dazu muß einfach der obige Zeilenumbruch-Filter erweitert werden. Wenn man einen Filter schreibt, der beliebige Dateitypen akzeptiert und diese in DeskJet-geeignete Ausgaben umwandelt, hat man wirklich einen cleveren Druck-Spooler.
So ein Filter wird Magic-Filter genannt. Man sollte sich nicht die Mühe machen und selber einen schreiben, solange man keine wirklich ungewöhnlichen Sachen drucken will. Es gibt bereits einige wirklich gute Filter. Der APS-Filter ist einer der besten Filter. Viele Linux-Distributionen werden auch mit Setup Tools für den Drucker ausgeliefert, die die Konfiguration von Druckern und passenden Filtern deutlich erleichtern.
Auf Grund von häufigen Nachfragen folgt hier eine Liste der Zugriffsrechte der wichtigen Dateien, wie sie auf meinem System gesetzt sind. Es gibt sicherlich bessere Möglichkeiten, aber so wurde das System installiert und es funktioniert.
-r-sr-sr-x 1 root lp /usr/bin/lpr*
-r-sr-sr-x 1 root lp /usr/bin/lprm*
-rwxr--r-- 1 root root /usr/sbin/lpd*
-r-xr-sr-x 1 root lp /usr/sbin/lpc*
drwxrwxr-x 4 root lp /var/spool/lpd/
drwxr-xr-x 2 root lp /var/spool/lpd/lp/
lpd
muß momentan als root aufgerufen werden, da nur root das
Recht hat, den Netzwerk-Port für lp zu belegen. Im Prinzip
könnte der Daemon nach der Initialisierung seine UID ändern, wie
das eigentlich jeder gut programmierte Daemon machen sollte.
Der lpd
tut dieses zur Zeit aber nicht.