Das FreeBSD-Handbuch
Zurück | Kapitel 9. Drucken | Weiter

# 9.4. Erweiterte Drucker-Konfiguration

Übersetzt von Johann Kois.

Dieser Abschnitt beschreibt den Einsatz von Filtern für das Drucken speziell formatierter Seiten oder von Deckblättern, das Drucken über ein Netzwerk sowie die Beschränkung und Verrechnung der Druckernutzung.

## 9.4.1. Filter

Obwohl LPD Netzwerkprotokolle, Warteschlangen, Zugriffskontrollen und andere für das Drucken wichtige Aspekte prinzipiell unterstützt, passiert ein Großteil der wirklichen Arbeit in den sogenannten Filtern. Dabei handelt es sich um Programme, die direkt mit einem Drucker kommunizieren und deren Gerätespezifika und spezielle Anforderungen erfüllen. Im einfachsten Fall installiert man nur einen reinen Textfilter, der mit beinahe allen Druckern funktionieren sollte. (Lesen Sie dazu auch den Abschnitt Den Text-Filter installieren.)

Um die erweiterten Fähigkeiten von Druckern auch einsetzen zu können, sollten Sie verstehen, wie Filter arbeiten, da diese für die Bereitstellung dieser Funktionen zuständig sind. Die schlechte Nachricht ist, dass Sie diese Filter bereitstellen müssen. Die gute Nachricht ist allerdings, dass diese in der Regel bereits vorhanden sind. Ist dies nicht der Fall, können Sie einen Filter meist relativ einfach selbst erstellen.

Der Filter `/usr/libexec/lpr/lpf` wird bereits mit FreeBSD geliefert. Er kümmert sich um die korrekte Behandlung von gelöschten Zeichen (das sogenannte Backspacing), um im Text enthaltene Tabulatoren, sowie um die Verrechnung von Druckaufträgen. Das ist aber auch alles, was dieser Filter kann. Zusätzliche Filter und für die Funktion von Filtern nötige Komponenten finden sich aber in der FreeBSD Ports-Sammlung.

Dieser Abschnitt behandelt folgende Themen:

- Der Abschnitt Die Funktionsweise von Filtern versucht, einen Überblick über die Rolle von Filtern innerhalb des Druckprozesses zu geben. Sie sollten diesen Abschnitt lesen, damit Sie verstehen, was “unter der Haube” passiert, wenn LPD einen Filter verwendet. Dieses Wissen wird Ihnen dabei helfen, Probleme, die bei Installation von Filtern für verschiedene Drucker entstehen können, vorauszusehen und zu beheben.

- LPD geht davon aus, dass jeder Drucker in der Lage ist, normalen Text zu drucken. Für PostScript®- (oder andere sprachbasierte) Drucker stellt dies allerdings ein Problem dar, da diese nicht in der Lage sind, normalen Text direkt zu drucken. Der Abschnitt Normalen Text auf PostScript-Druckern drucken beschreibt, wie Sie dieses Problem lösen können. Besitzen Sie einen PostScript-Drucker, sollten Sie diesen Abschnitt lesen.

- PostScript ist ein populäres Ausgabeformat, das von vielen Programmen unterstützt wird. Es ist sogar möglich, PostScript-Code direkt zu schreiben. Leider sind PostScript-Drucker in der Regel relativ teuer. Der Abschnitt PostScript auf Nicht-PostScript-Druckern emulieren beschreibt, wie Sie einen Textfilter anpassen müssen, um PostScript-Daten auf einem nicht-PostScript-fähigen Drucker auszugeben. Haben Sie keinen PostScript-Drucker, sollten Sie insbesondere diesen Abschnitt lesen.

- Der Abschnitt Konvertierungsfilter beschreibt eine Möglichkeit zur automatischen Konvertierung verschiedener Dateiformate in ein von Ihrem Drucker unterstütztes Format. Nachdem Sie diesen Abschnitt gelesen haben, werden Sie in der Lage sein, Ihren Drucker so zu konfigurieren, dass Sie durch die Eingabe von `lpr -t` troff-Daten, von `lpr -d` TeX-DVI-Daten, oder von `lpr -v` Rasterbilddaten drucken können. Daher sollten Sie diesen Abschnitt auf jeden Fall lesen.

- Im Abschnitt Ausgabefilter wird eine nur selten genutzte Eigenschaft von LPD, die sogenannten Ausgabefilter, beschrieben. Wenn Sie keine Deckblätter drucken müssen, können Sie diesen Abschnitt überspringen.

- Der Abschnitt lpf: Ein Textfilter beschreibt `lpf`, einen kompletten, wenn auch einfachen Textfilter für Zeilendrucker (oder auch Laserdrucker, die sich analog verhalten), der bereits mit FreeBSD geliefert wird. Wenn Sie nur am Ausdruck von reinem Text interessiert sind, oder wenn Ihr Drucker nur “Schrott” produziert, wenn er auf Backspace-Zeichen trifft, sollten Sie sich `lpf` näher ansehen.

> Anmerkung: Eine Kopie der verschiedenen Skripte finden Sie im Verzeichnis `/usr/share/examples/printing`.

### 9.4.1.1. Die Funktionsweise von Filtern

Bei einem Filter handelt es sich um ein ausführbares Programm, das von LPD gestartet wird, um den geräteabhängigen Teil der Kommunikation mit einem Drucker zu übernehmen.

Wenn LPD eine Datei über einen Druckauftrag drucken will, startet es ein Filterprogramm. Danach setzt es die Standardeingabe des Filters auf die zu druckende Datei, die Standardausgabe auf den Drucker und die Standardfehlerausgabe auf `/dev/console` (Voreinstellung) oder auf die über die Option `lf` in `/etc/printcap` festgelegte Datei.

Welcher Filter von LPD mit welchen Argumenten geladen wird, wird in der Datei `/etc/printcap` oder durch die Argumente, die der Anwender lpr(1) auf der Kommandozeile übergibt, festgelegt. Gibt der Anwender beispielsweise `lpr -t` ein, startet LPD über die `tf`-Fähigkeit den troff-Filter für den gewünschten Drucker. Wollen Sie hingegen normalen Text drucken, wird der `if`-Filter gestartet. (Für Ausnahmen von diesem Vorgehen lesen Sie bitte den Abschnitt Ausgabefilter.)

Es gibt drei Arten von Filtern, die Sie in `/etc/printcap` angeben können:

- Textfilter (die in der LPD-Dokumentation als input filter bezeichnet werden) sind für den Druck von normalem Text zuständig. Es handelt sich dabei um eine Art Standardfilter, da LPD von jedem Drucker erwartet, dass er normalen Text drucken kann. Aufgabe des Textfilters ist es, sicherzustellen, dass gelöschte Zeichen (Backspaces), Tabulatoren und andere Sonderzeichen Ihren Drucker nicht verwirren. Falls Sie für die Nutzung eines Druckers bezahlen müssen, kann der Textfilter über die Anzahl der gedruckten Zeilen auch die Anzahl der von Ihnen gedruckten Seiten ermitteln. Der Textfilter wird mit folgenden Argumenten gestartet:

  `filter-name` [-c] -w `width` -l `length` -i `indent` -n `login` -h `host` `acct-file`

  Die einzelnen Argumente haben folgende Bedeutung:

  `-c`

    Notwendig, wenn `lpr -l` verwendet wird.

  `width`

    Der Wert der in `/etc/printcap` festgelegten Option `pw` (page width). In der Voreinstellung ist dieser Wert auf 132 gesetzt.

  `length`

    Der Wert der `pl`-Fähigkeit (page length), Voreinstellung 66.

  `indent`

    Der durch `lpr -i` festgelegte Einzug, Voreinstellung 0.

  `login`

    Der Name des Benutzers, der die Datei druckt.

  `host`

    Der Rechner, auf dem der Druckauftrag gestartet wurde.

  `acct-file`

    Der Name der Verrechnungsdatei, in der die Ergebnisse der `af`-Fähigkeit gespeichert werden.

- Ein Konvertierungsfilter konvertiert verschiedene Dateiformate in ein Format, das Ihr Drucker auf Papier ausgeben kann. So kann etwa der ditroff-Schriftsatz nicht direkt gedruckt werden, daher müssen Sie einen Konvertierungsfilter installieren, um diese Daten in ein Format zu bringen, das Ihr Drucker verarbeiten und drucken kann. Der Abschnitt Konvertierungsfilter enthält ausführliche Informationen zu diesen Filtern. Konvertierungsfilter können auch zur Verrechnung verwendet werden. Sie werden mit folgenden Argumenten gestartet:

  `filter-name` -x `pixel-width` -y `pixel-height` -n `login` -h `host` `acct-file`

  `pixel-width` ist der Wert der `px`-Fähigkeit (Voreinstellung 0), während `pixel-height` dem Wert der `py`-Fähigkeit (Voreinstellung ebenfalls 0) entspricht.

- Ausgabefilter werden nur verwendet, wenn keine Textfilter vorhanden sind oder wenn Deckblätter benötigt werden. Der Abschnitt Ausgabefilter enthält weitere Informationen. Ausgabefilter unterstützen nur zwei Argumente:

  `filter-name` -w `width` -l `length`

  Beide Argumente entsprechen den Optionen `-w` und `-l` der Textfilter.

Alle Filter sollten mit folgenden Rückgabewerten (Exitcodes) beendet werden:

exit 0

  Der Filter hat die Datei erfolgreich gedruckt.

exit 1

  Der Filter war nicht in der Lage, die Datei zu drucken und meldet diesen Exitcode an LPD, um die Datei erneut zu drucken. LPD startet daraufhin den Filter erneut.

exit 2

  Der Filter war nicht in der Lage, die Datei zu drucken. Bei diesem Exitcode soll LPD aber nicht versuchen, die Datei erneut zu drucken, sondern den Druckauftrag verwerfen.

`/usr/libexec/lpr/lpf`, der mit FreeBSD gelieferte Textfilter, nutzt die Argumente page width und page length, um festzulegen, wann ein Seitenumbruch (form feed) gesendet werden soll sowie zur Verrechnung von Druckaufträgen. Dazu werden der Benutzername, der für den Druckauftrag verwendete Rechner sowie die Verrechnungsdatei ausgewertet, um die entsprechenden Einträge zu erstellen.

Wenn Sie auf der Suche nach Filtern sind, achten Sie darauf, dass diese LPD-kompatibel sind. Dazu müssen diese die oben beschriebenen Argumente unterstützen. Wenn Sie planen, Ihre Filter selbst zu erstellen, müssen diese ebenfalls die gleichen Argumente und Exitcodes unterstützen.

### 9.4.1.2. Normalen Text auf PostScript®-Druckern drucken

Sie sind der alleinige Benutzer Ihres Computers und Ihres PostScript-Druckers und Sie sind sich sicher, dass Sie niemals normalen Text an Ihren Drucker senden werden? Außerdem werden Sie niemals ein Programm verwenden, um normalen Text auszudrucken? Nur wenn dies alles zutrifft, können Sie diesen Abschnitt überspringen.

Wollen Sie allerdings sowohl PostScript als auch normalen Text drucken, müssen Sie Ihren Drucker zuvor entsprechend konfigurieren. Dazu muss Ihr Textfilter in der Lage sein, zu unterscheiden, ob es sich bei einem ankommenden Druckauftrag um normalen Text oder um PostScript-Daten handelt. Jeder PostScript-Druckauftrag muss mit den Zeichen `%!` beginnen (sehen Sie in Ihrem Druckerhandbuch nach, ob Ihr Drucker weitere Sprachen unterstützt). Sind dies die beiden ersten Zeichen eines Druckauftrages, so handelt es sich um PostScript-Daten, die direkt gedruckt werden können. Fehlen diese Zeichen allerdings, muss der Textfilter den Inhalt der Datei nach PostScript konvertieren, bevor die Datei gedruckt werden kann.

Wie funktioniert diese Unterscheidung?

Haben Sie einen seriellen Drucker, können Sie `lprps` installieren. `lprps` ist ein PostScript-Druckerfilter, der eine Zweiwegekommunikation mit einem Drucker ermöglicht. Er aktualisiert die Druckerstatusdatei mit Protokollinformationen des Druckers. Dadurch sind Anwender und Administratoren in der Lage, den genauen Zustand des Druckers zu prüfen (durch Meldungen wie “`toner low`” oder “`paper jam`”). Wichtiger ist allerdings, dass `lprps` `psif` enthält, ein Programm, das feststellen kann, ob ein ankommender Druckauftrag normalen Text enthält. Ist dies der Fall, wird `textps` (das ebenfalls mit `lprps` geliefert wird) aufgerufen und die Datei nach PostScript konvertiert. Danach kann `lprps` die Datei an den Drucker senden.

`lprps` ist in der FreeBSD Ports-Sammlung enthalten. Je nach der von Ihnen verwendeten Papiergröße installieren Sie dazu den Port `print/lprps-a4` oder `print/lprps-letter`. Nach der Installation müssen Sie nur noch den Pfad zum Programm `psif` angeben, das als Teil von `lprps` installiert wird. Haben Sie `lprps` über die Ports-Sammlung installiert, fügen Sie folgende Zeile in den Eintrag Ihres PostScript-Druckers in `/etc/printcap` ein:

    :if=/usr/local/libexec/psif:

Zusätzlich sollten Sie die `rw`-Fähigkeit aktivieren, um LPD im Schreib- und Lesemodus zu öffnen.

Haben Sie hingegen einen parallelen PostScript-Drucker, was eine Zweiwegekommunikation mit Ihrem Drucker (auf die `lprps` angewiesen ist) unmöglich macht, können Sie das folgende Shell-Skript verwenden:

    #!/bin/sh
    #
    #  psif - Drucke PostScript oder normalen Text auf einem PostScript-Drucker
    #  Script-Version; das ist NICHT die mit lprps gelieferte Version!
    #  Installiert unter:  /usr/local/libexec/psif
    #

    IFS="" read -r first_line
    first_two_chars=`expr "$first_line" : '\(..\)'`

    if [ "$first_two_chars" = "%!" ]; then
        #
        #  PostScript - einfach drucken.
        #
        echo "$first_line" && cat && printf "\004" && exit 0
        exit 2
    else
        #
        #  Normaler Text - zuerst konvertieren, dann drucken.
        #
        ( echo "$first_line"; cat ) | /usr/local/bin/textps && printf "\004" && exit 0
        exit 2
    fi

Für dieses Skript wurde `textps` als seperates Programm installiert, um normalen Text nach PostScript zu konvertieren. Sie können aber auch jeden anderen Text-nach-PostScript-Konverter verwenden. Die FreeBSD Ports-Sammlung enthält mit `a2ps` ein umfangreiches Programm zur Konvertierung von normalem Text nach PostScript.

### 9.4.1.3. PostScript auf Nicht-PostScript-Druckern emulieren

Bei PostScript handelt es sich um den de facto-Standard für hochwertigen Schriftsatz und Druck. Leider ist PostScript aber auch ein teurer Standard. Glücklicherweise hat Aladdin Enterprises daher eine freie PostScript-ähnliche Implementierung namens Ghostscript entwickelt, die auch unter FreeBSD lauffähig ist. Ghostscript kann fast jede PostScript-Datei lesen und auf den verschiedensten Geräten ausgeben, darunter auch auf vielen Nicht-PostScript-Druckern. Durch die Installation von Ghostscript und die Nutzung eines speziellen Textfilters erreichen Sie, dass sich Ihr Nicht-PostScript-Drucker wie ein echter PostScript-Drucker verhält.

Ghostscript ist in verschiedenen Versionen in der FreeBSD Ports-Sammlung enhalten, die am häfigsten verwendete Version ist `print/ghostscript-gpl`.

Um PostScript zu emulieren, muss der Textfilter erkennen, ob er eine PostScript-Datei drucken soll. Ist dies nicht der Fall, wird die Datei direkt an den Drucker geschickt. Anderenfalls wird die Datei an Ghostscript übergeben, das die Datei in ein Format konvertiert, das Ihr Drucker versteht.

Dazu ein Beispiel. Das folgende Skript ist ein Textfilter für den Drucker DeskJet 500 von Hewlett Packard. Nutzen Sie einen anderen Drucker, müssen Sie die Option `-sDEVICE` beim Aufruf von `gs` (Ghostscript) entsprechend anpassen. Eine Liste der von Ghostscript unterstützten Geräte erhalten Sie durch die Eingabe von `gs -h` auf der Kommandozeile.

    #!/bin/sh
    #
    #  ifhp - Ghostscript-emuliertes PostScript auf einem HP DeskJet 500 drucken
    #  Installiert unter:  /usr/local/libexec/ifhp

    #
    #  LF als CR+LF behandeln (um einen "Treppeneffekt" auf HP/PCL-Drucker
    #  zu vermeiden)
    #
    printf "\033&k2G" || exit 2

    #
    #  Lies die ersten zwei Zeichen der Datei
    #
    IFS="" read -r first_line
    first_two_chars=`expr "$first_line" : '\(..\)'`

    if [ "$first_two_chars" = "%!" ]; then
        #
        #  Oh.  Es ist PostScript; mit Ghostscript konvertieren, danach drucken.
        #
        /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \
          -sOutputFile=- - && exit 0
    else
        #
        #  Normaler Text oder HP/PCL, einfach direkt drucken.  Ans Ende setzen wir
        #  einen Seitenumbruch (also ein Form Feed), damit auch die letzte Seite
        #  ausgeworfen wird.
        #
        echo "$first_line" && cat && printf "\033&l0H" &&
    exit 0
    fi

    exit 2

Zuletzt müssen Sie LPD noch durch die `if`-Fähigkeit über den neuen Filter informieren:

    :if=/usr/local/libexec/ifhp:

Das ist alles. Ab sofort sollte sowohl ein `lpr normaler.text` als auch ein `lpr wasauchimmer.ps` funktionieren und beide Dateien sollten problemlos gedruckt werden.

### 9.4.1.4. Konvertierungsfilter

Nachdem Sie Ihren Drucker wie unter Einfache Drucker-Konfiguration eingerichtet haben, wollen Sie wahrscheinlich einige Konvertierungsfilter installieren, damit Sie (abgesehen von ASCII-Text) auch Ihre Lieblings-Dateiformate drucken können.

#### 9.4.1.4.1. Warum sollte ich einen Konvertierungsfilter installieren?

Konvertierungsfilter erleichtern das Drucken von verschiedenen Dateiformaten. Nehmen wir beispielsweise an, dass Sie sehr viel mit dem TeX-Satzsystem arbeiten und über einen PostScript-Drucker verfügen. Eine vom TeX-System erzeugte DVI-Datei kann erst dann gedruckt werden, nachdem diese nach PostScript konvertiert wurde. Dazu geben Sie Folgendes ein:

    % dvips seaweed-analysis.dvi
    % lpr seaweed-analysis.ps

Haben Sie einen Konvertierungsfilter für DVI-Dateien installiert, können Sie die manuelle Konvertierung überspringen, da dies nun LPD für Sie erledigt. Wollen Sie eine DVI-Datei drucken, geben Sie nur noch den folgenden Befehl ein:

    % lpr -d seaweed-analysis.dvi

Durch die Verwendung der Option `-d` wurde LPD angewiesen, unsere DVI-Datei vor dem Druck zu konvertieren. Der Abschnitt Formatierungs- und Konvertierungsoptionen beschreibt die dabei möglichen Optionen.

Für jede Konvertierungsoption, die Ihr Drucker unterstützen soll, müssen Sie einen eigenen Konvertierungsfilter installieren und dessen Pfad in der Datei `/etc/printcap` angeben. Ein Konvertierungsfilter verhält sich im Prinzip wie ein Textfilter bei einer einfachen Druckerkonfiguration (lesen Sie dazu auch den Abschnitt Den Textfilter installieren), allerdings konvertiert er die Datei in ein Format, das Ihr Drucker versteht, anstatt normalen Text zu drucken.

#### 9.4.1.4.2. Welche Konvertierungsfilter sollte ich installieren?

Sie sollten nur Filter installieren, die Sie auch benötigen. Wenn Sie sehr viele DVI-Dateien drucken, sollten Sie auch einen DVI-Konvertierungsfilter installieren. Müssen Sie viele troff-Daten drucken, ist ein troff-Filter hilfreich.

Die folgende Tabelle listet die von LPD unterstützten Filter sowie die Einträge in `/etc/printcap` auf, mit denen Sie diese Fähigkeiten aktivieren. Zusätzlich wird angegeben, wie Sie `lpr` jeweils aufrufen müssen:

Dateityp | `/etc/printcap`-Fähigkeit | `lpr`-Option
--- | --- | ---
cifplot | `cf` | `-c`
DVI | `df` | `-d`
plot | `gf` | `-g`
ditroff | `nf` | `-n`
FORTRAN-Text | `rf` | `-f`
troff | `tf` | `-f`
Rasterdaten | `vf` | `-v`
Normaler Text | `if` | keine, `-p`, or `-l`

Wollen Sie also `lpr -d` verwenden, muss die `df`-Fähigkeit in `/etc/printcap` aktiviert sein.

Obwohl manche Leute etwas anderes behaupten, sind Formate wie FORTRAN-Text und -Plot inzwischen nahezu obsolet. Wenn Sie diese Formate dennoch benötigen, installieren Sie einfach einen angepassten Filter. Wollen Sie beispielsweise zwar Printerleaf-Dateien (also Dateien des Desktop Publishing-Programms von Interleaf), aber keine Plotdateien drucken, so können Sie einen Printerleaf-Konvertierungsfilter installieren, der es durch die Aktivierung der `gf`-Fähigkeit erlaubt, diese Dateien direkt zu drucken. Nun müssen Sie Ihren Mitarbeitern nur noch mitteilen, dass `lpr -g` nun für “drucke Printerleaf-Dateien” steht.

#### 9.4.1.4.3. Konvertierungsfilter installieren

Da Konvertierungsfilter nicht zum Basissystem von FreeBSD gehören, sollten diese unter `/usr/local` installiert werden. Häufig wird das Verzeichnis `/usr/local/libexec` verwendet, da es sich bei Konvertierungsfiltern um spezielle Programme handelt, die nur von LPD, aber nicht von einem normalen Benutzer gestartet werden.

Um einen Konvertierungsfilter zu aktivieren, müssen Sie dessen Pfad zusätzlich zur benötigten Fähigkeit in der Datei `/etc/printcap` eintragen.

In unserem Beispiel wollen wir einen DVI-Konvertierungsfilter für den Drucker `bamboo` installieren. Unsere bereits bekannte `/etc/printcap` wurde allerdings um die `df`-Fähigkeit für den Drucker `bamboo` erweitert.

    #
    #  /etc/printcap des Rechners rose - neuer df-Filter für bamboo
    #
    rattan|line|diablo|lp|Diablo 630 Line Printer:\
            :sh:sd=/var/spool/lpd/rattan:\
            :lp=/dev/lpt0:\
            :if=/usr/local/libexec/if-simple:

    bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
            :sh:sd=/var/spool/lpd/bamboo:\
            :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\
            :if=/usr/local/libexec/psif:\
            :df=/usr/local/libexec/psdf:

Beim DVI-Filter handelt es sich um ein Shell-Skript namens `/usr/local/libexec/psdf`:

    #!/bin/sh
    #
    #  psdf - DVI-nach-PostScript Druckerfilter
    #  Installiert unter:  /usr/local/libexec/psdf
    #
    #  Wird von lpd aktiviert, wenn der Nutzer lpr -d eingibt.
    #
    exec /usr/local/bin/dvips -f | /usr/local/libexec/lprps "$@"

Dieses Skript startet `dvips` im Filtermodus (durch das Argument `-f` wird der Druckauftrag über die Standardeingabe entgegengenommen). Danach wird der PostScript-Druckerfilter `lprps` (lesen Sie dazu auch den Abschnitt Drucken von reinen Textdateien auf einem PostScript-Drucker) mit den von LPD übergebenen Argumenten gestartet. `lprps` wiederum nutzt diese Argumente, um die gedruckten Seiten zu verrechnen.

#### 9.4.1.4.4. Beispiele für Konvertierungsfilter

Da es keine verbindliche Prozedur zur Installation eines Druckerfilters gibt, folgen nun weitere Beispiele. Verwenden Sie diese, um Ihre eigenen Filter zu erstellen. Falls ein Filter Ihren Anforderungen bereits entspricht, können Sie ihn auch direkt verwenden.

Das erste Beispiel beschreibt einen Konvertierungsfilter für GIF-Dateien für den Drucker LaserJet III-Si von Hewlett Packard:

    #!/bin/sh
    #
    #  hpvf - Konvertiert GIF-Dateien nach HP/PCL, danach wird gedruckt.
    #  Installiert unter:  /usr/local/libexec/hpvf

    PATH=/usr/X11R6/bin:$PATH; export PATH
    giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \
        && exit 0 \
        || exit 2

Dieser Filter konvertiert eine GIF-Datei in eine portable Anymap, diese in ein portables Graustufenbild, dieses wiederum in eine portable Bitmap, die schließlich in ein LaserJet/PCL-kompatibles Format umgewandelt wird.

`/etc/printcap` muss für einen Drucker, der diesen Filter nutzen will, folgenden Eintrag enthalten:

    #
    #  /etc/printcap des Rechners orchid
    #
    teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
            :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\
            :if=/usr/local/libexec/hpif:\
            :vf=/usr/local/libexec/hpvf:

Das folgende Skript ist ein Konvertierungsfilter, der das Drucken von troff-Daten des groff-Textsatzsystems auf dem PostScript-Drucker `bamboo` ermöglicht:

    #!/bin/sh
    #
    #  pstf - Konvertiert groff's troff-Daten nach PS, dann wird gedruckt.
    #  Installiert unter:  /usr/local/libexec/pstf
    #
    exec grops | /usr/local/libexec/lprps "$@"

Dieses Skript nutzt wiederum `lprps`, um mit dem Drucker zu kommunizieren. Wäre der Drucker an einem parallelen Port angeschlossen, würde das Skript so aussehen:

    #!/bin/sh
    #
    #  pstf - Konvertiert groff's troff-Daten nach PS, danach wird gedruckt.
    #  Installiert unter:  /usr/local/libexec/pstf
    #
    exec grops

Das ist alles. Um den Filter verwenden zu können, müssen Sie ihn allerdings noch in `/etc/printcap` aktivieren:

    :tf=/usr/local/libexec/pstf:

Das nächste Skript ist ein FORTRAN-Textfilter für jeden Drucker, der normalen Text direkt drucken kann und der hier für den Drucker `teak` installiert wird:

    #!/bin/sh
    #
    # hprf - FORTRAN-Textfilter für den Drucker LaserJet 3si:
    # Installiert unter:  /usr/local/libexec/hprf
    #

    printf "\033&k2G" && fpr && printf "\033&l0H" &&
     exit 0
    exit 2

Zusätzlich benötigen wir wiederum einen Eintrag in `/etc/printcap`, um diesen Filter für den Drucker `teak` zu aktivieren:

    :rf=/usr/local/libexec/hprf:

Das letzte Beispiel ist etwas komplexer. Es soll ein DVI-Filter für den bereits erwähnten LaserJet-Drucker `teak` installiert werden. Der erste Teil ist einfach: Sie müssen den Pfad des DVI-Filters in `/etc/printcap` eintragen:

    :df=/usr/local/libexec/hpdf:

Nun kommt der schwierige Teil: Sie müssen den Filter funktionsfähig machen. Dazu benötigen Sie einen DVI-nach-LaserJet/PCL-Konverter. Glücklicherweise enthält die FreeBSD Ports-Sammlung mit `dvi2xx` ein solches Programm. Nach der Installation des Ports verfügen wir über das Programm `dvilj2p`, das zur Konvertierung von DVI-Daten in zu den Druckern LaserJet IIp, LaserJet III, sowie LaserJet 2000 kompatible Codes benötigt wird.

Durch den Einsatz von `dvilj2p` wird der Filter `hpdf` relativ komplex, da `dvilj2p` nicht von der Standardeingabe lesen kann, sondern als Eingabe einen Dateinamen erwartet. Zusätzlich muss der Dateiname auf `.dvi` enden, daher ist die Verwendung von `/dev/fd/0` als Standardeingabe problematisch. Wir können diese Problem aber umgehen, indem wir einen temporären Dateinamen symbolisch nach `/dev/fd/0` linken. Dadurch wird `dvilj2p` gezwungen, dennoch von der Standardeingabe zu lesen.

Das letzte Problem, das wir noch lösen müssen, ist, dass wir `/tmp` nicht als temporären Link verwenden können. Symbolische Links gehören dem User sowie der Gruppe `bin`. Der Filter läuft aber als User `daemon`. Außerdem ist `/tmp` durch ein Sticky-Bit gesichert. Daher kann der Filter den Link zwar erzeugen, ein Aufräumen ist aber nicht mehr möglich, weil sich die Eigentümer des Filters und des temporären Verzeichnisses unterscheiden.

Daher legt der Filter den symbolischen Link im Arbeitsverzeichnis an, das gleichzeitig als Spooling-Verzeichnis dient (festgelegt durch die Aktivierung der `sd`-Fähigkeit in `/etc/printcap`). Das Arbeitsverzeichnis ist ein idealer Ort für den Filter, insbesondere da dieses (manchmal) sogar über mehr freien Speicherplatz als `/tmp` verfügt.

Mit diesen Informationen sind wir nun in der Lage, den Filter zu entwickeln:

    #!/bin/sh
    #
    #  hpdf - DVI-Daten auf einen HP/PCL-Drucker drucken
    #  Installiert unter:  /usr/local/libexec/hpdf

    PATH=/usr/local/bin:$PATH; export PATH

    #
    #  Eine Funktion zum Aufräumen unserer temporären Dateien.
    #  Diese finden sich im Arbeitsverzeichnis, das wir auch als
    #  Spooling-Verzeichnis für unseren Drucker verwenden werden.
    #
    cleanup() {
       rm -f hpdf$$.dvi
    }

    #
    #  Eine Funktion, um fatale Fehler zu behandeln.  Dazu die Meldung
    #  ausgeben, danach ein exit 2.  Dadurch weiß LPD, dass es
    #  den Auftrag nicht noch einmal drucken soll.
    #
    fatal() {
        echo "$@" 1>&2
        cleanup
        exit 2
    }

    #
    #  Wenn ein Anwender den Auftrag entfernt, sendet LPD ein SIGINT, daher
    #  wollen wir SIGINT und einige andere Signale abfangen (trappen), um
    #  nach der Konvertierung aufräumen zu können.
    #
    trap cleanup 1 2 15

    #
    #  Bevor wir anfangen, räumen wir noch auf.  Sicher ist sicher.
    #
    cleanup

    #
    #  Die DVI-Eingabedatei auf die Standardeingabe linken (die zu druckende
    #  Datei).
    #
    ln -s /dev/fd/0 hpdf$$.dvi || fatal "Konnte Symlink nicht anlegen!"

    #
    #  Umwandeln: LF = CR+LF
    #
    printf "\033&k2G" || fatal "Konnte Drucker nicht initialisieren!"

    #
    #  Konvertieren und drucken.  Da der Rückgabewert von dvilj2p
    #  unzuverlässig ist, ignorieren wir ihn einfach.
    #
    dvilj2p -M1 -q -e- dfhp$$.dvi

    #
    #  Aufräumen und beenden.
    #
    cleanup
    exit 0

#### 9.4.1.4.5. Automatische Konvertierung: Eine Alternative zu Konvertierungsfiltern

Alle in diesem Abschnitt besprochenen Konvertierungsfilter sind zwar sehr hilfreich, allerdings müssen Sie nach wie vor bei jedem Aufruf von lpr(1) angeben, welchen Filter sie verwenden wollen, was mit der Zeit sicher nervend wird. Schlimmer ist allerdings, dass die Auswahl eines unpassenden Filters dazu führen kann, dass Sie Hunderte Seiten Papier ausdrucken.

Statt also Konvertierungsfilter zu installieren, könnten Sie den Textfilter (der ohnehin der Standardfilter ist) verwenden, um den zu druckenden Dateityp zu erkennen und anschließend den korrekten Konvertierungsfilter auszuwählen. Um den Dateityp zu bestimmen, können Sie beispielsweise `file` verwenden. Leider ist es bei einigen Dateitypen problematisch, diese zu unterscheiden. Daher könnten Sie für diese Dateitypen dennoch einen Konvertierungsfilter installieren.

Die FreeBSD Ports-Sammlung enthält mit `apsfilter` einen Textfilter, der diese automatische Konvertierung durchführen kann. Er ist in der Lage, normalen Text sowie PostScript- und DVI-Dateien zu erkennen, diese zu konvertieren und auf Ihren Drucker auszugeben.

### 9.4.1.5. Ausgabefilter

LPD unterstützt noch eine weitere Filterart, die sogenannten Ausgabefilter. Diese sind - analog zu einem Textfilter - für den Druck von normalem Text ausgelegt, allerdings verfügen sie im Vergleich zu diesen nur über sehr eingeschränkte Fähigkeiten. Wenn Sie einen Ausgabefilter (aber keinen Textfilter) verwenden, dann

- startet LPD nur einen Ausgabefilter für den kompletten Druckauftrag, statt für jede Datei des Auftrags einen eigenen Filter zu starten.

- kümmert sich LPD nicht darum, den Beginn oder das Ende einer Datei innerhalb des Druckauftrages zu finden.

- übergibt LPD weder den Benutzer- noch den Rechnernamen desjenigen, der den Druckauftrag erteilt hat, an den Ausgabefilter, was eine Verrechnung von Druckaufträgen unmöglich macht. Ausgabefilter unterstützen insgesamt nur zwei Argumente:

  `filter-name` -w `width` -l `length`

  `width` basiert auf der `pw`-Fähigkeit, `length` hingegen auf der `pl`-Fähigkeit des gewählten Druckers.

Lassen Sie sich von dieser angeblichen Einfachheit eines Ausgabefilters nicht täuschen. Ausgabefilter sind beispielsweise nicht dazu in der Lage, jede Datei eines Druckauftrages auf einer neuen Seite zu drucken. Dazu benötigen Sie einen Textfilter (die im Abschnitt Den Textfilter installieren beschrieben werden). Außerdem sind Ausgabefilter in Wirklichkeit komplexer, da sie den gesendeten Bytestrom nicht nur auf Sonderzeichen hin untersuchen müssen, sondern auch die Übertragung von Signalen für LPD übernehmen müssen.

Sie benötigen Ausgabefilter aber dann, wenn Sie Deckblätter drucken wollen, da dazu Escape-Sequenzen und Initialisierungsstrings erforderlich sind. (Es ist allerdings nicht möglich, den Druck dieser Deckblätter zu verrechnen, da LPD keine Benutzer- oder Rechnerinformationen an den Ausgabefilter übergibt.)

LPD kann für den gleichen Drucker sowohl Ausgabefilter als auch Textfilter verwenden. In solchen Fällen verwendet LPD den Ausgabefilter nur für den Druck von Deckblättern (die im Abschnitt Deckblätter näher beschrieben werden). Nach dem Druck des Deckblattes erwartet LPD, dass sich der Ausgabefilter selbst beendet. Dazu werden zwei Bytes an den Ausgabefilter gesendet: ASCII 031, gefolgt von ASCII 001. Wenn ein Ausgabefilter diese zwei Bytes (031, 001) empfängt, sendet er das Signal `SIGSTOP` an sich selbst. Nachdem LPD den Rest des Druckauftrages erledigt hat, wird der Ausgabefilter erneut gestartet, indem ein `SIGCONT` an den Ausgabefilter gesendet wird.

Haben Sie nur einen Ausgabefilter, aber keinen Textfilter installiert, dann verwendet LPD den Ausgabefilter auch für den Druck von normalem Text. Wie bereits erwähnt, werden dabei allerdings alle Dateien des Druckauftrags unmittelbar hintereinander gedruckt, Seitenumbrüche oder ein zusätzlicher Papiervorschub sind also nicht möglich. Da dieses Verhalten von Ihnen wahrscheinlich nicht gewünscht wird, werden Sie in fast allen Fällen einen zusätzlichen Textfilter benötigen.

Der weiter oben beschriebene Textfilter `lpf` kann auch als Ausgabefilter verwendet werden. Wenn Sie nur einen funktionierenden Ausgabefilter benötigen, aber nicht den dafür benötigten Code (zur Zeichenerkennung und zum Senden von Signalen) schreiben wollen, sollten Sie sich `lpf` näher ansehen. Sie können `lpf` auch in ein Shell-Skript einbinden, um von Ihrem Drucker benötigte Initialisierungscodes zu verarbeiten.

### 9.4.1.6. `lpf`: Ein Textfilter

Der Textfilter (Eingabefilter) `/usr/libexec/lpr/lpf` wird bereits mit FreeBSD geliefert. Er erlaubt das Einrücken der Ausgabe (über `lpr -i`), die Übergabe von Zeichen-Literalen (über `lpr -l`), das Anpassen der Druckposition bei gelöschten Zeichen (Backspaces) oder Tabulatoren, sowie die Verrechnung gedruckter Seiten. Zusätzlich kann dieser Textfilter auch als Ausgabefilter arbeiten.

`lpf` ist für viele verschiedene Druckumgebungen geeignet. Zwar ist dieser Textfilter nicht in der Lage, Initialisierungssequenzen an einen Drucker zu senden, dieses Problem kann allerdings durch das Schreiben und Ausführen eines Shell-Skripts (das diese Funktion übernimmt) und das anschließende Aufrufen von `lpf` gelöst werden.

Damit Sie `lpf` für die Verrechnung von Druckaufträgen einsetzen können, müssen Sie die korrekten Werte für die `pw`- und `pl`-Fähigkeiten in `/etc/printcap` eintragen. `lpf` verwendet diese Werte, um festzustellen, wieviel Text auf eine Seite passt und wieviele Seiten im Druckauftrag enthalten sind. Weitere Informationen zur Verrechnung der Druckernutzung enthält der Abschnitt Die Druckernutzung verrechnen.

## 9.4.2. Deckblätter

Wenn Sie viele Benutzer mit verschiedenen Druckern verwalten müssen, sollten Sie Deckblätter als notwendiges Übel akzeptieren.

Deckblätter (manchmal auch als Bannerseiten oder burst pages bezeichnet) geben an, wem die Ausgabe eines Druckauftrags gehört. Sie werden normalerweise in großen fetten Buchstaben gedruckt, manchmal sogar mit zusätzlicher Umrandung, damit man sie leichter von den tatsächlichen Seiten eines Druckauftrages unterscheiden kann. Der Nachteil von Deckblättern ist allerdings, dass es sich dabei um eine zusätzliche zu druckende Seite handelt, die in der Regel bereits nach wenigen Minuten wieder im Papierkorb landet. Da aber für jeden Druckauftrag nur ein einziges Deckblatt gedruckt wird, ist der Papierverbrauch in den meisten Fällen tolerierbar.

Das LPD-System kann Deckblätter automatisch erzeugen, wenn Ihr Drucker normalen Text direkt drucken kann. Haben Sie hingegen einen PostScript-Drucker, benötigen Sie ein externes Programm, um die Deckblätter zu generieren (Lesen Sie dazu auch den Abschnitt Deckblätter auf PostScript-Druckern erzeugen.).

### 9.4.2.1. Deckblätter aktivieren

Im Abschnitt Einfache Drucker-Konfiguration haben wir die Ausgabe von Deckblättern durch die die Angabe der Option `sh` (suppress header) in `/etc/printcap` deaktiviert. Um die Ausgabe von Deckblättern wieder zu aktivieren, müssen Sie daher die `sh`-Fähigkeit wieder entfernen.

Das klingt zu einfach? Wo ist der Haken?

Sie haben recht. Es ist möglich, dass Sie einen Ausgabefilter verwenden müssen, um die nötigen Initialisierungsstrings an den Drucker zu senden. Das folgende Beispiel beschreibt einen Ausgabefilter für PCL-kompatible Drucker von Hewlett Packard:

    #!/bin/sh
    #
    #  hpof - Ausgabefilter für PCL-kompatible Drucker von Hewlett Packard
    #  Installiert unter:  /usr/local/libexec/hpof

    printf "\033&k2G" || exit 2
    exec /usr/libexec/lpr/lpf

Geben Sie den Pfad des Ausgabefilters über die `of`-Fähigkeit an. Weitere Informationen finden Sie im Abschnitt Ausgabefilter.

Das nächste Beispiel beschreibt die Datei `/etc/printcap` des bereits erwähnten Druckers `teak`. Allerdings sind nun die Ausgabe von Deckblättern sowie der vorhin beschriebene Ausgabefilter enthalten:

    #
    #  /etc/printcap für den Rechner orchid
    #
    teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
            :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\
            :if=/usr/local/libexec/hpif:\
            :vf=/usr/local/libexec/hpvf:\
            :of=/usr/local/libexec/hpof:

Wenn ein Anwender nun einen Druckauftrag an den Drucker `teak` schickt, wird für jeden Druckauftrag ein Deckblatt erstellt. Benötigt ein Anwender keine Deckblätter, kann er die Ausgabe dieser Seiten durch die Verwendung von `lpr -h` unterdrücken. Weitere, für die Ausgabe von Deckblättern interessante lpr(1)-Optionen finden Sie im Abschnitt Deckblattoptionen.

> Anmerkung: LPD verwendet ein Form Feed, um das Deckblatt abzuschließen. Wenn Ihr Drucker ein anderes Zeichen verwendet, um eine Seite auszuwerfen, geben Sie dieses über die `ff`-Fähigkeit in `/etc/printcap` an.

### 9.4.2.2. Deckblätter kontrollieren

Haben Sie die Ausgabe von Deckblättern aktiviert, gibt LPD eine ganze Seite in großen Buchstaben aus, die den Anwender, den verwendeten Rechner sowie den Druckauftrag beschreiben. Das folgende Beispiel ist ein Deckblatt für den Druckauftrag outline, der von kelly auf dem Rechner `rose` erstellt wurde:

          k                   ll       ll
          k                    l        l
          k                    l        l
          k   k     eeee       l        l     y    y
          k  k     e    e      l        l     y    y
          k k      eeeeee      l        l     y    y
          kk k     e           l        l     y    y
          k   k    e    e      l        l     y   yy
          k    k    eeee      lll      lll     yyy y
                                                   y
                                              y    y
                                               yyyy

                                       ll
                              t         l        i
                              t         l
           oooo    u    u   ttttt       l       ii     n nnn     eeee
          o    o   u    u     t         l        i     nn   n   e    e
          o    o   u    u     t         l        i     n    n   eeeeee
          o    o   u    u     t         l        i     n    n   e
          o    o   u   uu     t  t      l        i     n    n   e    e
           oooo     uuu u      tt      lll      iii    n    n    eeee

          r rrr     oooo     ssss     eeee
          rr   r   o    o   s    s   e    e
          r        o    o    ss      eeeeee
          r        o    o      ss    e
          r        o    o   s    s   e    e
          r         oooo     ssss     eeee

                                                  Job:  outline
                                                  Date: Sun Sep 17 11:04:58 1995

LPD fügt ein Form Feed an diesen Text an, damit der eigentliche Druckauftrag auf einer neuen Seite gestartet wird (es sei denn, Sie haben die `sf`-Fähigkeit (suppress form feeds) des jeweiligen Druckers in `/etc/printcap` aktiviert).

Wenn Sie dies wüschen, kann LPD auch nur ein kurzes Deckblatt ausgeben. Dazu verwenden Sie die Option `sb` (short banner) in `/etc/printcap`. Dadurch erhalten Sie ein Deckblatt ähnlich dem folgenden:

    rose:kelly  Job: outline  Date: Sun Sep 17 11:07:51 1995

In der Voreinstellung druckt LPD zuerst das Deckblatt und danach den eigentlichen Druckauftrag. Um diese Reihenfolge umzukehren, geben Sie die Option `hl` (header last) in `/etc/printcap` ans.

### 9.4.2.3. Deckblätter verrechnen

Wenn Sie die in LPD eingebaute Funktion zur Erstellung von Deckblättern verwenden, werden Sie auf folgendes Paradigma stoßen: Deckblätter müssen kostenlos sein.

Warum ist das so?

Weil der Ausgabefilter das einzige externe Programm ist, das zum Zeitpunkt der Erstellung des Deckblatts eine Verrechnung durchführen könnte. Da Ausgabefilter aber weder über Benutzer- noch über Rechnerinformationen verfügen, ist es nicht möglich, einen Druckauftrag einem bestimmten Benutzer zuzuordnen. Da ein Benutzer die Ausgabe von Deckblättern über `lpr -h` unterdrücken kann, ist es auch nicht möglich, die Vorgabe “verrechne eine zusätzliche Seite” in den Text- oder Konvertierungsfilter (die über die zur Verrechnung nötigen Benutzer- und Rechnerinformationen verfügen) aufzunehmen, weil Benutzer sonst für Deckblätter bezahlen müssten, die sie nicht gedruckt haben.

Es ist ebenfalls nicht ausreichend, jeden Filter eigene Deckblätter erzeugen zu lassen (und sie dadurch verrechnen zu können). Wollte ein Benutzer durch ein `lpr -h` die Ausgabe eines Deckblattes unterdrücken, würde dieses nun trotzdem verrechnet werden, da LPD keine Informationen über die Verwendung der Option `-h` an einen Filter weitergibt.

Welche Möglichkeiten habe ich nun?

Sie können:

- Das Paradigma von LPD einfach akzeptieren und die Deckblätter gratis abgeben.

- Eine alternatives Drucksystem wie LPRng installieren. Der Abschnitt Alternativen zum Standard-Drucksystem beschreibt verschiedene Drucksysteme, die LPD ersetzen können.

- Schreiben Sie einen intelligenten Ausgabefilter. Normalerweise kümmert sich ein Ausgabefilter nur um die Initialisierung des Druckers oder um eine einfache Zeichenkonvertierung. Außerdem eignet er sich für die Ausgabe von Deckblättern und normalem Text, wenn Sie keinen Text- oder Eingabefilter installiert haben. Haben Sie allerdings einen Textfilter installiert, verwendet LPD Ausgabefilter nur für die Ausgabe von Deckblättern. Ein Ausgabefilter kann den Text des von LPD erzeugten Deckblattes untersuchen, um festzustellen, welcher Benutzer und welcher Rechner den Druckauftrag gestartet hat. Leider weiß der Ausgabefilter auch mit dieser Methode nicht, welche Datei er zur Verrechnung verwenden soll (da der Name dieser Datei durch die `af`-Fähigkeit übergeben wird). Wenn Sie eine Standard-Verrechnungsdatei verwenden, können Sie diese in den Ausgabefilter einbauen. Um den Text des Deckblattes zu untersuchen, verwenden Sie die `sh`-Fähigkeit (short header) in `/etc/printcap`. Falls Ihnen das zuviel Aufwand ist, freuen sich Ihre Benutzer sicher darüber, wenn Sie ihnen den kostenlosen Druck von Deckblättern erlauben.

### 9.4.2.4. Deckblätter auf PostScript-Druckern ausgeben

In der Regel erzeugt LPD ein Deckblatt mit normalem Text, das für viele verschiedene Drucker geeignet ist. Da PostScript-Drucker normalen Text aber nicht drucken können, ist die LPD-Funktion zur Erstellung von Deckblättern auf diesen Drucker relativ sinnlos.

Es sei denn, jeder Text- und Konvertierungsfilter erzeugt über den Benutzer- und Rechnernamen sein eigenes, für den jeweiligen Drucker geeignetes Deckblatt. Das Problem dieser Methode ist allerdings, dass ein Anwender auch dann ein Deckblatt erhält, wenn er dies über `lpr -h` verhindern wollte.

Das folgende Skript benötigt drei Argumente (den Loginnamen des Benutzers, den Rechnernamen und den Namen des Druckauftrages), um daraus ein einfaches PostScript-Deckblatt zu erzeugen:

    #!/bin/sh
    #
    #  make-ps-header - ein PostScript-Deckblatt auf stdout ausgeben
    #  Installiert unter:  /sr/local/libexec/make-ps-header
    #

    #
    #  Die folgenden Werte sind PostScript-Einheiten (72 pro Zoll).
    #  Passen Sie diese Werte für A4 oder die von Ihnen verwendete
    #  Papiergröße an:
    #
    page_width=612
    page_height=792
    border=72

    #
    #  Argumente prüfen
    #
    if [ $# -ne 3 ]; then
        echo "Usage: `basename $0` <user> <host> <job>" 1>&2
        exit 1
    fi

    #
    #  Diese Werte in Variablen speichern, damit der PostScript-Code
    #  übersichtlicher wird.
    #
    user=$1
    host=$2
    job=$3
    date=`date`

    #
    #  Sende den PostScript-Code an stdout.
    #
    exec cat <<EOF
    %!PS

    %
    %  Sicherstellen, dass es keine unerwünschten Wechselwirkungen mit
    %  dem folgenden Druckauftrag gibt.
    %
    save

    %
    %  Ziehe eine fette Umrandung.
    %
    $border $border moveto
    $page_width $border 2 mul sub 0 rlineto
    0 $page_height $border 2 mul sub rlineto
    currentscreen 3 -1 roll pop 100 3 1 roll setscreen
    $border 2 mul $page_width sub 0 rlineto closepath
    0.8 setgray 10 setlinewidth stroke 0 setgray

    %
    %  Zeige den Benutzernamen groß und fett an.
    %
    /Helvetica-Bold findfont 64 scalefont setfont
    $page_width ($user) stringwidth pop sub 2 div $page_height 200 sub moveto
    ($user) show

    %
    %  Und nun zeige noch die Einzelheiten an.
    %
    /Helvetica findfont 14 scalefont setfont
    /y 200 def
    [ (Job:) (Host:) (Date:) ] {
    200 y moveto show /y y 18 sub def }
    forall

    /Helvetica-Bold findfont 14 scalefont setfont
    /y 200 def
    [ ($job) ($host) ($date) ] {
            270 y moveto show /y y 18 sub def
    } forall

    %
    % Das wars.
    %
    restore
    showpage
    EOF

Nun kann jeder Konvertierungs- oder Textfilter dieses Skript aufrufen, um zuerst das Deckblatt zu erzeugen und danach den Druckauftrag zu drucken. Das nächste Beispiel enthält den bereits beschriebenen DVI-Konvertierungsfilter, der hier um die Funktion zur Erzeugung eines Deckblatts erweitert wurde:

    #!/bin/sh
    #
    #  psdf - DVI-nach-PostScript - Druckerfilter
    #  Installiert unter:  /usr/local/libexec/psdf
    #
    #  Wird von lpd aufgerufen, wenn der Benutzer lpr -d verwendet.
    #

    orig_args="$@"

    fail() {
        echo "$@" 1>&2
        exit 2
    }

    while getopts "x:y:n:h:" option; do
        case $option in
            x|y)  ;; # Ignore
            n)    login=$OPTARG ;;
            h)    host=$OPTARG ;;
            *)    echo "LPD started `basename $0` wrong." 1>&2
                  exit 2
                  ;;
        esac
    done

    [ "$login" ] || fail "No login name"
    [ "$host" ] || fail "No host name"

    ( /usr/local/libexec/make-ps-header $login $host "DVI File"
      /usr/local/bin/dvips -f ) | eval /usr/local/libexec/lprps $orig_args

Beachten Sie, dass der Filter die Liste der Argumente überprüft, um den Benutzer- und den Rechnernamen zu ermitteln. Dieser Vorgang ist prinzipiell für alle Filter identisch. Der Textfilter benötigt allerdings etwas andere Argumente, die im Abschnitt Die Funktionsweise von Filtern beschrieben werden.

Wie bereits erwähnt, deaktiviert diese Methode leider die “suppress header page”-Option (also die Option `-h`) von `lpr`. Benutzer können danach den Ausdruck eines Deckblattes nicht mehr verhindern, da der angepasste Filter zu jedem Druckauftrag automatisch ein Deckblatt erstellt.

Damit ein Benutzer bei Bedarf den Ausdruck eines Deckblatts dennoch unterbinden kann, müssen Sie auch hier den im Abschnitt Deckblätter verrechnen beschriebenen Trick einsetzen: Schreiben Sie einen Ausgabefilter, der das von LPD erzeugte Deckblatt untersucht und daraus eine PostScript-Version erzeugt. Wenn der Benutzer den Druckauftrag mit `lpr -h` verschickt, erzeugt LPD kein Deckblatt, was in weiterer Folge auch für Ihren Ausgabefilter gilt. Soll hingegen ein Deckblatt erzeugt werden, liest der Ausgabefilter den von LPD übergebenen Text und erzeugt daraus ein für Ihren PostScript-Drucker geeignetes Deckblatt.

Haben Sie Ihren PostScript-Drucker über eine serielle Verbindung angeschlossen, können Sie auch `lprps` verwenden. In diesem Paket ist mit `psof` auch ein Ausgabefilter enthalten, der die eben beschriebenen Funktionen übernehmen kann. Beachten Sie aber, dass Sie mit `psof` keine Deckblätter verrechnen können.

## 9.4.3. Drucken über ein Netzwerk

FreeBSD unterstützt das Drucken über ein Netzwerk, also den Versand von Druckaufträgen an einen entfernten Drucker. Man unterscheidet dabei zwei Möglichkeiten:

- Den Zugriff auf einen an einem entfernten Rechner angeschlossenen Drucker. Sie konfigurieren dabei auf Ihrem System einen Drucker, der über eine konventionelle serielle oder parallele Verbindung an einem anderen Rechner angeschlossen ist. Danach richten Sie LPD auf dem entfernten System so ein, dass andere Drucker über das Netzwerk auf diesen Drucker zugreifen können. Der Abschnitt Auf entfernten Rechnern installierte Drucker beschreibt, wie Sie dazu vorgehen müssen.

- Den Zugriff auf einen direkt an ein Netzwerk angeschlossenen Drucker. Ein solcher Drucker verfügt anstelle (oder zusätzlich zu) einer parallelen oder seriellen Schnittstelle über eine Netzwerkschnittstelle. Ein solcher Drucker kann sich auf zwei Arten verhalten:

  - Er kann das LPD-Protokoll direkt unterstützen und sogar Druckjobs von entfernten Rechner verwalten. In diesem Fall verhält sich der Drucker wie ein normaler Rechner, auf dem LPD läuft. Lesen Sie den Abschnitt Auf entfernten Rechnern installierte Drucker, um einen solchen Drucker einzurichten.

  - Er könnte Verbindungen über ein Netzwerk unterstützen. In diesem Fall “verbinden” Sie den Drucker mit einem Rechner Ihres Netzwerks, der danach für die Verwaltung von Druckaufträgen sowie den tatsächlichen Druck verantwortlich ist. Der Abschnitt Drucker mit direkter TCP-Schnittstelle enthält Hinweise zur Installation derartiger Drucker.

### 9.4.3.1. Auf entfernten Rechnern installierte Drucker

Das LPD-Drucksystem unterstützt den Versand von Druckaufträgen an andere Rechner, auf denen entweder LPD läuft oder die zu LPD kompatibel sind. Dadurch können Sie einen Drucker auf einem Rechner installieren und von anderen Rechnern des Netzwerks darauf zugreifen. Außerdem werden Drucker mit direkter TCP-Schnittstelle unterstützt, wenn diese das LPD-Protokoll unterstützen.

Um diese Art des Druckens über ein Netzwerk zu aktivieren, installieren Sie zuerst Ihren Drucker auf einem Rechner Ihres Netzwerks, dem sogenannten printer host. Die dazu nötigen Schritte werden im Abschnitt Einfache Drucker-Konfiguration beschrieben. Falls Sie eine erweiterte Druckerkonfiguration benötigen, sollten Sie auch den Abschnitt Erweiterte Drucker-Konfiguration lesen. Danach testen Sie, ob der Drucker alle von Ihnen aktivierten LPD-Fähigkeiten unterstützt. Stellen Sie auch sicher, dass Ihr lokales System berechtigt ist, den LPD-Dienst auf dem entfernten System zu nutzen (lesen Sie dazu den Abschnitt Druckaufträge auf entfernten Druckern beschränken).

Wenn Sie einen Drucker mit einer zu LPD kompatiblen Netzwerkschnittstelle verwenden, handelt es sich beim printer host um den Drucker selbst, und der Druckername ist der von Ihnen für diesen Drucker vorgegebene Name. Lesen Sie die Dokumentation Ihres Druckers und/oder der Netzwerkschnittstelle Ihres Druckers, um dies zu klären.

> Tipp: Wenn Sie einen Hewlett Packard Laserjet-Drucker verwenden, sorgt der Druckername `text` für eine automatische LF-zu-CRLF-Konvertierung. In diesem Fall wird das `hpif`-Skript nicht benötigt.

Danach müssen Sie auf jedem Rechner, der auf diesen Drucker zugreifen soll, einen entsprechenden Eintrag in deren `/etc/printcap` aufnehmen. Dazu werden folgende Informationen benötigt:

1. Der Name des Eintrags. Entspricht in der Regel dem Eintrag auf dem printer host.

2. Lassen Sie den Eintrag für die `lp`-Fähigkeit leer, schreiben Sie also `:lp=:`.

3. Erzeugen Sie ein Spooling-Verzeichnis und geben Sie dessen Pfad über die `sd`-Fähigkeit an. LPD speichert Ihre Druckaufträge in diesem Verzeichnis, bevor sie an den Drucker geschickt werden.

4. Geben Sie den Namen des printer hosts über die `rm`-Fähigkeit an.

5. Geben Sie den Namen des Druckers (auf dem printer host) über die `rp`-Fähigkeit an.

Das ist alles. Sie benötigen weder Konvertierungsfilter, noch Seitengrößen oder sonstige Angaben in Ihrer lokalen `/etc/printcap`.

Dazu ein Beispiel. Der Rechner `rose` verfügt über zwei Drucker, `bamboo` und `rattan`. Wir wollen nun allen Benutzern des Rechners `orchid` erlauben, diese Drucker zu verwenden. Es folgt nun wieder die bereits aus dem Abschnitt Deckblätter verwenden bekannte `/etc/printcap` für den Rechner `orchid`. Diese enthielt bereits einen Eintrag für den Drucker `teak`. Zusätzlich tragen wir nun die zwei Drucker des Rechners `rose` ein:

    #
    #  /etc/printcap für den Rechner orchid - mit zusätzlichen
    #  Einträgen für die (entfernten) Drucker auf dem Rechner rose
    #

    #
    #  teak ist ein lokaler Drucker und direkt mit orchid verbunden:
    #
    teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
            :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\
            :if=/usr/local/libexec/ifhp:\
            :vf=/usr/local/libexec/vfhp:\
            :of=/usr/local/libexec/ofhp:

    #
    #  rattan ist mit rose verbunden, Druckaufträge für rattan gehen daher
    #  an den Rechner rose:
    #
    rattan|line|diablo|lp|Diablo 630 Line Printer:\
            :lp=:rm=rose:rp=rattan:sd=/var/spool/lpd/rattan:

    #
    #  bamboo ist ebenfalls mit rose verbunden:
    #
    bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
            :lp=:rm=rose:rp=bamboo:sd=/var/spool/lpd/bamboo:

Nun müssen wir nur noch die Spooling-Verzeichnisse auf dem Rechner `orchid` erzeugen:

    # mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo
    # chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo
    # chown daemon:daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo

Damit können Benutzer des Rechners `orchid` die Drucker `rattan` und `bamboo` verwenden. Gibt ein Benutzer auf `orchid` beispielsweise

    % lpr -P bamboo -d sushi-review.dvi

ein, würde LPD auf dem Rechner `orchid` den Druckauftrag in das Spooling-Verzeichnis `/var/spool/lpd/bamboo` kopieren und feststellen, dass es sich um einen DVI-Auftrag handelt. Sobald `rose` über genug freien Platz im `bamboo`-Spooling-Verzeichnis verfügt, würden die beiden LPDs die Datei auf den Rechner `rose` transferieren. Diese Datei verbleibt danach in der Druckerwarteschlange des Rechners `rose`, bis der Ausdruck der Datei abgeschlossen ist. Vor dem Ausdruck würde die Datei noch von DVI nach PostScript konvertiert werden, da es sich bei `bamboo` um einen an den Rechner `rose` angeschlossenen PostScript-Drucker handelt.

### 9.4.3.2. Drucker mit direkter TCP-Schnittstelle

Wenn Sie eine Netzwerkkarte für Ihren Drucker kaufen, können Sie zwei verschiedene Versionen wählen: Eine Version, die ein Drucksystem emuliert (die teure Version), oder eine Version, die sich verhält, als wäre der Drucker an eine serielle oder parallele Schnittstelle angeschlossen (die billige Version). Dieser Abschnitt beschreibt die billige Variante. Bevorzugen Sie die teure Variante, sollten Sie den Abschnitt Auf entfernten Rechnern installierte Drucker nochmals lesen.

Das Format der Datei `/etc/printcap` erlaubt es Ihnen, anzugeben, welche serielle oder parallele Schnittstelle verwendet werden soll und (falls Sie eine serielle Schnittstelle verwenden) welche Parameter (Baudrate, Flußkontrolle, Behandlung von Tabulatoren, Konvertierung von neuen Zeilen und andere mehr) Sie verwenden wollen. Es gibt allerdings keine Möglichkeit, eine Verbindung zu einem Drucker zu definieren, der einen TCP/IP- oder einem anderem Netzwerkport auf Druckaufträge hin abfragt.

Um Daten an einen Netzwerkdrucker zu schicken, müssen Sie daher ein Kommunikationsprogramm entwickeln, das von Text- und Konvertierungsfiltern aufgerufen werden kann. Dazu ein Beispiel. Das Skript `netprint` übernimmt alle Daten von der Standardeingabe und schickt sie an einen Netzwerkdrucker. `netprint` erwartet zwei Argumente: Als erstes Argument wird der Hostname des Druckers und als zweites Argument der Port, über den die Verbindung erfolgen soll, übergeben. Dabei handelt sich allerdings um eine Ein-Wege-Kommunikation (von FreeBSD zum Drucker). Viele Netzwerkdrucker unterstützen aber auch eine Zwei-Wege-Kommunikation, deren Vorteile (Abfrage des Druckerstatus, die Verrechnung von Druckaufträgen und andere mehr) Sie vielleicht nutzen wollen.

    #!/usr/bin/perl
    #
    #  netprint - Textfilter für einen Netzwerkdrucker
    #  Installiert unter:  /usr/local/libexec/netprint
    #
    $#ARGV eq 1 || die "Usage: $0 <printer-hostname> <port-number>";

    $printer_host = $ARGV[0];
    $printer_port = $ARGV[1];

    require 'sys/socket.ph';

    ($ignore, $ignore, $protocol) = getprotobyname('tcp');
    ($ignore, $ignore, $ignore, $ignore, $address)
        = gethostbyname($printer_host);

    $sockaddr = pack('S n a4 x8', &AF_INET, $printer_port, $address);

    socket(PRINTER, &PF_INET, &SOCK_STREAM, $protocol)
        || die "Can't create TCP/IP stream socket: $!";
    connect(PRINTER, $sockaddr) || die "Can't contact $printer_host: $!";
    while (<STDIN>) { print PRINTER; }
    exit 0;

Dieses Skript kann für verschiedene Filter eingesetzt werden. Das folgende Beispiel verwendet den an ein Netzwerk angeschlossenen Zeilendrucker Diablo 750-N. Dieser Drucker empfängt zu druckende Daten auf dem Port 5100. Der Hostname des Druckers lautet `scrivener`. Daher sieht der Textfilter für diesen Drucker wie folgt aus:

    #!/bin/sh
    #
    #  diablo-if-net - Textfilter für den Diablo-Drucker `scrivener'.
    #  Drucker lauscht auf Port 5100.
    #  Installiert unter:  /usr/local/libexec/diablo-if-net
    #
    exec /usr/libexec/lpr/lpf "$@" | /usr/local/libexec/netprint scrivener 5100

## 9.4.4. Den Druckerzugriff beschränken

Dieser Abschnitt beschreibt, wie Sie den Druckerzugriff beschränken können. Das LPD-Drucksystem erlaubt Ihnen die Kontrolle darüber, wer lokal oder über ein Netzwerk auf einen Drucker zugreifen darf, ob mehrere Kopien erstellt werden dürfen und wie groß Druckaufträge und Druckerwarteschlangen werden dürfen.

### 9.4.4.1. Den Ausdruck von mehreren Kopien verhindern

Das LPD-System macht es dem einzelnen Benutzer einfach, mehrere Kopien einer Datei zu drucken. So werden mit `lpr -#5` beispielsweise fünf Kopien jeder Datei des Druckauftrags erstellt. Ob dies gut oder schlecht ist, müssen Sie selbst entscheiden.

Wenn Sie der Meinung sind, dass multiple Kopien eine unnötige Beanspruchung Ihres Druckers darstellen, sollten Sie die `-#`-Opion von lpr(1) deaktivieren, indem Sie die `sc`-Fähigkeit in Ihre `/etc/printcap` aufnehmen. Verwendet ein Benutzer dennoch die Option `-#`, erhält er daraufhin folgende Meldung:

    lpr: multiple copies are not allowed

Wenn Sie den Zugriff auf einen entfernten Drucker (wie in Abschnitt Auf entfernten Rechnern installierte Drucker beschrieben) konfiguriert haben, müssen Sie die `sc`-Fähigkeit auch auf den entfernten Rechnern, die auf Ihren Drucker zugreifen dürfen, in `/etc/printcap` eintragen, damit Benutzer diese Vorgabe nicht durch den Wechsel auf einen anderen Rechner umgehen können.

Dazu ein Beispiel. Es handelt sich dabei um die Datei `/etc/printcap` auf dem Rechner `rose`. Der Drucker `rattan` soll multiple Kopien zulassen, auf dem Laserdrucker `bamboo` sollen multiple Kopien hingegen nicht erlaubt sein, daher müssen wir für diesen Drucker die `sc`-Fähigkeit aktivieren:

    #
    #  /etc/printcap für den Rechner rose - multiple Kopien auf bamboo verbieten
    #
    rattan|line|diablo|lp|Diablo 630 Line Printer:\
            :sh:sd=/var/spool/lpd/rattan:\
            :lp=/dev/lpt0:\
            :if=/usr/local/libexec/if-simple:

    bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
            :sh:sd=/var/spool/lpd/bamboo:sc:\
            :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\
            :if=/usr/local/libexec/psif:\
            :df=/usr/local/libexec/psdf:

Außerdem müssen wir noch die `sc`-Fähigkeit in der Datei `/etc/printcap` des Rechners `orchid` aktivieren. Parallel dazu untersagen wir das Erstellen von multiplen Kopien auf dem Drucker `teak`:

    #
    #  /etc/printcap für den Rechner orchid - lokal machen wir keine multiplen Kopien
    #  Lokaler Drucker teak oder entfernter Drucker bamboo:
    teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
            :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:sc:\
            :if=/usr/local/libexec/ifhp:\
            :vf=/usr/local/libexec/vfhp:\
            :of=/usr/local/libexec/ofhp:

    rattan|line|diablo|lp|Diablo 630 Line Printer:\
            :lp=:rm=rose:rp=rattan:sd=/var/spool/lpd/rattan:

    bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
            :lp=:rm=rose:rp=bamboo:sd=/var/spool/lpd/bamboo:sc:

Durch die Verwendung der `sc`-Fähigkeit ist zwar die Verwendung von `lpr -#` nicht mehr möglich, ein Benutzer kann aber weiterhin lpr(1) mehrmals hintereinander aufrufen oder eine Datei mehrfach in den gleichen Druckauftrag aufnehmen:

    % lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign

Auch dieser Mißbrauch Ihres Druckers kann verhindert werden, falls Sie dies wünschen. Diese Maßnahmen werden in diesem Abschnitt allerdings nicht behandelt.

### 9.4.4.2. Den Zugriff auf bestimmte Drucker beschränken

Sie können angeben, wer auf welchem Drucker drucken darf, wenn Sie den Gruppenmechanismus von UNIX® in Kombination mit der `rg`-Fähigkeit von `/etc/printcap` einsetzen. Weisen Sie dazu alle Benutzer, die auf einen Drucker zugreifen dürfen, einer gemeinsamen Gruppe zu und geben Sie diese Gruppe über die `rg`-Fähigkeit an.

Benutzer, die dieser Gruppe nicht angehören (dies gilt auch für `root`), erhalten die Meldung “`lpr: Not a member of the restricted group`” wenn Sie diesen Drucker verwenden wollen.

Analog zur `sc`-Fähigkeit (suppress multiple copies) müssen Sie die `rg`-Fähigkeit auch auf allen entfernten Rechnern aktivieren, die auf Ihren Drucker zugreifen dürfen (lesen Sie dazu auch den Abschnitt Auf entfernten Rechnern installierte Drucker).

Wollen wir beispielsweise allen Benutzern die Verwendung des Druckers `rattan`, aber nur Mitgliedern der Gruppe `artists` die Verwendung des Druckers `bamboo` erlauben, passen wir die bereits bekannte `/etc/printcap` des Rechners `rose` entsprechend an:

    #
    #  /etc/printcap des Rechners rose - Zugriffsbeschränkung für bamboo
    #
    rattan|line|diablo|lp|Diablo 630 Line Printer:\
            :sh:sd=/var/spool/lpd/rattan:\
            :lp=/dev/lpt0:\
            :if=/usr/local/libexec/if-simple:

    bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
            :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:\
            :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\
            :if=/usr/local/libexec/psif:\
            :df=/usr/local/libexec/psdf:

Die Datei `/etc/printcap` des Rechners `orchid` wird dadurch nicht beeinflusst. Jeder Benutzer des Rechners `orchid` kann also weiterhin den Drucker `bamboo` verwenden.

> Anmerkung: Für jeden Drucker kann nur eine einzige priviligierte Gruppe erstellt werden.

### 9.4.4.3. Die Größe von Druckaufträgen kontrollieren

Wenn Sie viele Benutzer haben, die Ihre Drucker verwenden dürfen, werden Sie wahrscheinlich eine Obergrenze für Dateien angeben wollen, die Benutzer an Ihren Drucker senden dürfen. Dies ist sinnvoll, weil Speicherplatz für Spooling-Verzeichnisse nur begrenzt verfügbar ist und Sie stets sicherstellen müssen, dass auch die Druckaufträge anderer Benutzer verarbeitet werden können.

LPD verwendet die `mx`-Fähigkeit, um die maximal erlaubte Größe von Dateien eines Druckauftrags anzugeben. Dieser Wert wird in 1.024 Bytes großen `BUFSIZ`-Blöcken angegeben. Setzen Sie diesen Wert auf Null, gibt es keine Größenbeschränkung. Existiert die `mx`-Fähigkeit hingegen überhaupt nicht, so gilt ein Limit von 1.000 Blöcken.

> Anmerkung: Diese Limits gelten nur für die Größe von Dateien innerhalb eines Druckauftrages, nicht aber für die Gesamtgröße des Druckauftrags.

LPD lehnt eine Datei auch dann nicht ab, wenn sie das Limit des Druckers überschreitet. Vielmehr wird die Datei bis zum Erreichen des Limits in die Warteschlange geladen, danach wird der Druck gestartet. Der das Limit überschreitende Rest wird hingegen verworfen und nicht gedruckt!

Mit diesem Wissen können wir nun Limits für die Drucker `rattan` und `bamboo` definieren. Da PostScript-Dateien der Gruppe `artists` in der Regel sehr groß sind, setzen wir ein Limit von fünf Megabytes. Für den Druck von normalen Text (auf dem Drucker `rattan`) setzen wir hingegen kein Limit:

    #
    #  /etc/printcap für den Rechner rose
    #

    #
    #  Kein Größenlimit:
    #
    rattan|line|diablo|lp|Diablo 630 Line Printer:\
            :sh:mx#0:sd=/var/spool/lpd/rattan:\
            :lp=/dev/lpt0:\
            :if=/usr/local/libexec/if-simple:

    #
    #  Ein Limit von 5 Megabyte:
    #
    bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
            :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\
            :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\
            :if=/usr/local/libexec/psif:\
            :df=/usr/local/libexec/psdf:

Auch diese Limits gelten nur für lokale Benutzer. Wenn Sie den Zugriff auf Ihren Drucker auch über ein Netzwerk erlauben wollen, unterliegen die Benutzer dieser Rechner diesen Limits nicht. Daher müssen Sie diese Limits über die `mx`-Fähigkeit auch in der `/etc/printcap` jedes Rechners definieren, der Ihren Drucker verwenden darf. Der Abschnitt Auf entfernten Rechnern installierte Drucker enthält weitere Informationen zum Drucken über ein Netzwerk.

Es gibt eine weitere Möglichkeit, um die Größe von Druckaufträgen von entfernten Rechnern zu beschränken. Lesen Sie dazu den Abschnitt Druckaufträge von entfernten Rechnern beschränken.

### 9.4.4.4. Druckaufträge von entfernten Rechnern beschränken

Das LPD-System bietet mehrere Möglichkeiten, um Druckaufträge zu beschränken, die auf entfernten Rechnern gestartet wurden:

Rechner beschränken

  Sie können festlegen, von welchen entfernten Rechnern ein lokaler LPD Druckaufträge annimmt, indem Sie die Dateien `/etc/hosts.equiv` sowie `/etc/hosts.lpd` entsprechend anpassen. LPD überprüft diese Dateien, um festzustellen, ob ein Druckauftrag von einem Rechner stammt, der in einer dieser Dateien aufgeführt ist. Ist dies nicht der Fall, lehnt LPD den Druckauftrag ab.

  Der Aufbau dieser Datei ist sehr einfach: Jede Zeile enthält einen einzigen Rechnernamen. Beachten Sie aber, dass `/etc/hosts.equiv` auch vom ruserok(3)-Protokoll benötigt wird und Änderungen dieser Datei auch Programme wie rsh(1) und rcp(1) beeinflussen können.

  Das folgende Beispiel beschreibt die Datei `/etc/hosts.lpd` auf dem Rechner `rose`:

      orchid
      violet
      madrigal.fishbaum.de

  Durch diese Vorgaben akzeptiert `rose` nur noch Druckaufträge von den Rechnern `orchid`, `violet`, und `madrigal.fishbaum.de`. Versucht ein anderer Rechner, auf den LPD von `rose` zuzugreifen, wird dieser Druckauftrag abgelehnt werden.

Größenbeschränkungen

  Sie können festlegen, wieviel Speicherplatz auf dem Dateisystem, in dem das Spooling-Verzeichnis liegt, mindestens frei sein muss. Dazu erzeugen Sie im Spooling-Verzeichnis Ihres lokalen Druckers die Datei `minfree`. In dieser Datei geben Sie an, wieviele 512 Byte große Blöcke auf Ihrer Platte frei sein müssen, damit ein Druckauftrag von einem entfernten Rechner akzeptiert wird.

  Durch diese Vorgabe können Sie sicherstellen, dass Benutzer von entfernten Rechnern Ihr Dateisystem nicht “zumüllen”. Außerdem können Sie damit lokale Benutzer bevorzugen, da diese auch dann noch Druckaufträge erteilen dürfen, wenn der verfügbare Plattenplatz unter das in der Datei `minfree` definierte Limit gefallen ist.

  Legen wir nun die Datei `minfree` für den Drucker `bamboo` an. Zuerst untersuchen wir `/etc/printcap`, um das Spooling-Verzeichnis für diesen Drucker zu finden. Das folgende Beispiel zeigt den Eintrag für den Drucker `bamboo`:

      bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
              :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\
              :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:mx#5000:\
              :if=/usr/local/libexec/psif:\
              :df=/usr/local/libexec/psdf:

  Das Spooling-Verzeichnis wird über die `sd`-Fähigkeit festgelegt. Wir wollen, dass mindestens drei Megabyte (also 6144 Blöcke) freier Plattenplatz vorhanden sein müssen, damit LPD einen Druckauftrag von einem entfernten Rechner akzeptiert:

      # echo 6144 > /var/spool/lpd/bamboo/minfree

Benutzer beschränken

  Sie können auch festlegen, welche entfernten Benutzer Ihren lokalen Drucker verwenden dürfen, indem Sie die `rs`-Fähigkeit in `/etc/printcap` definieren. Wenn für den Eintrag eines lokalen Druckers die `rs`-Fähigkeit definiert ist, akzeptiert LPD Druckaufträge von entfernten Rechnern nur dann, wenn der Benutzer, der den Druckauftrag gesendet hat, auch über ein gleichnamiges Benutzerkonto auf dem lokalen Rechner verfügt. Ist dies nicht der Fall, lehnt LPD den Druckauftrag ab.

  Diese Fähigkeit ist besonders in Umgebungen nützlich, in denen beispielsweise verschiedene Abteilungen ein gemeinsames Netzwerk teilen, wobei einige Benutzer zu mehreren Abteilungen gehören. Haben diese Benutzer auch ein Benutzerkonto auf Ihrem System, so können sie Ihren Drucker auch von ihrer eigenen Abteilung aus nutzen. Wollen Sie zwar den Zugriff auf Ihren Drucker, nicht aber den Zugriff auf Ihre übrigen Ressourcen erlauben, können Sie für diese Benutzer einen sogenannten “Token-Account” ohne Heimatverzeichnis und mit einer nutzlosen Shell wie `/usr/bin/false` erstellen.

## 9.4.5. Die Druckernutzung verrechnen

Sie wollen die Nutzung Ihrer Drucker kostenpflichtig machen? Warum auch nicht? Papier und Tinte kosten Geld. Auch eine regelmäßige Wartung muss bezahlt werden. Nachdem Sie einen Preis festgelegt haben, den Sie für jede gedruckte Seite verrechnen wollen, stellt sich die Frage, wie Sie die Verrechnung der Druckkosten technisch umsetzen können.

Die schlechte Nachricht ist, dass das LPD-System dabei wenig hilfreich ist. Die Verrechnung von Druckaufträgen hängt stark vom verwendeten Drucker, den zu druckenden Dateiformaten und Ihren Anforderungen an die Verrechnung der Druckernutzung ab.

Um die Verrechnung der Druckernutzung zu implementieren, müssen Sie sowohl Ihre Textfilter (um den Druck von normalem Text abzurechnen) als auch Ihre Konvertierungsfilter (um den Druck sonstiger Formate abzurechnen) entsprechend anpassen, damit diese die Zahl der gedruckten Seiten ermitteln können. Leider können Sie dazu nicht einen einfachen Ausgabefilter verwenden, da diese die Verrechnung von Druckaufträgen nicht unterstützen. Weitere Informationen zu den verschiedenen Filterarten finden Sie im Abschnitt Filter.

Prinzipiell gibt es zwei Möglichkeiten, wie Sie diese Verrechnung umsetzen können:

- Die periodische Verrechnung wird häufiger verwendet, da sie einfacher zu implementieren ist. Wenn ein Druckauftrag ausgeführt wird, schreibt der Filter den Benutzer, den verwendeten Rechner sowie die Anzahl der gedruckten Seiten in eine Verrechnungsdatei. Nach einem zu definierenden Zeitraum werden diese Dateien ausgewertet, die Gesamtzahl der von einem Benutzer gedruckten Seiten bestimmt und dem jeweiligen Benutzer verrechnet. Danach werden alle Protokolldateien zurückgesetzt, und die Protokollierung beginnt von Neuem.

- Die unmittelbare Verrechnung wird nur selten eingesetzt, das sie schwieriger zu implementieren ist. Bei dieser Methode wird der Druckauftrag verrechnet, sobald der Drucker verwendet wird. Dadurch können Sie beispielsweise verhindern, dass ein Benutzer seine erlaubte “Druckquote” überschreitet. Zusätzlich können Sie es Ihren Benutzern erlauben, deren Druckquote abzufragen oder anzupassen. Allerdings benötigen Sie eine Datenbank, um Benutzer und deren Quoten verwalten zu können.

Das LPD-Drucksystem unterstützt beide Methoden. Allerdings müssen Sie die benötigen Filter sowie den zur Verrechnung nötigen Code selbst bereitstellen. Der Vorteil dabei ist allerdings, dass Sie in der Wahl Ihrer Verrechnungsmethode äußerst flexibel sind. So können Sie sich etwa für die periodische oder die unmittelbare Verrechnung entscheiden. Sie können festlegen, welche Informationen Sie erfassen wollen: Benutzernamen, Rechnernamen, die Art der Druckaufträge, die Anzahl der gedruckten Seiten, den Papierverbrauch, den Zeitaufwand für die Bearbeitung eines Druckauftrages und viele andere mehr. Dazu müssen Sie Ihre Filter entsprechend anpassen, damit diese Informationen erfassst und gespeichert werden.

### 9.4.5.1. Kurzanleitung für die Implementierung der Druckerverrechnung

FreeBSD bietet Ihnen zwei Programme, um eine periodische Verrechnung rasch zu implementieren. Dabei handelt es sich um den im Abschnitt lpf: Ein Textfilter behandelten Textfilter sowie um pac(8), ein Programm, mit dem Sie Einträge aus Verrechnungsdateien auslesen und aufsummieren können.

Wie bereits im Abschnitt Filter erwähnt, startet LPD den Text- oder Konvertierungsfilter mit dem Namen der Verrechnungsdatei als Argument. Dadurch weiß der Filter, in welche Datei er einen Verrechnungseintrag schreiben soll. Der Name dieser Datei wird über die `af`-Fähigkeit in `/etc/printcap` festgelegt. Falls die Datei nicht über einen absoluten Pfad angegeben wird, handelt es sich um einen Pfad relativ zum Spooling-Verzeichnis.

LPD startet `lpf` mit den Argumenten page width und page length, die über die `pw`- und `pl`-Fähigkeit definiert werden. `lpf` verwendet diese Argumente danach, um den Papierverbrauch zu bestimmen. Nachdem die Datei an den Drucker geschickt wurde, wird ein Verrechnungseintrag in die Verrechnungsdatei geschrieben. Ein solcher Eintrag sieht dabei ähnlich den folgenden aus:

    2.00 rose:andy
    3.00 rose:kelly
    3.00 orchid:mary
    5.00 orchid:mary
    2.00 orchid:zhang

Sie sollten für jeden Drucker eine eigene Verrechnungsdatei verwenden, da `lpf` die Verrechnungsdatei nicht sperren kann. Sind also gleichzeitig zwei `lpf`-Instanzen aktiv, kann es dazu kommen, dass Ihre Verrechnungsdatei zerstört wird, wenn beide Instanzen gleichzeitig in die gleiche Datei schreiben. Damit für jeden Drucker eine eigene Verrechnungsdatei angelegt wird, fügen Sie den Eintrag `af=acct` in `/etc/printcap` ein. Dadurch wird für jeden Drucker eine separate Verrechnungsdatei mit dem Namen `acct` im Spooling-Verzeichnis des jeweiligen Druckers erzeugt.

Wenn Sie Ihre Daten erfasst haben und die entstandenen Kosten Ihren Benutzern verrechnen wollen, starten Sie pac(8). Dazu wechseln Sie in das Spooling-Verzeichnis des auszuwertenden Druckers und geben `pac` ein. Dadurch erhalten Sie eine Ausgabe ähnlich der folgenden:

      Login               pages/feet   runs    price
    orchid:kelly                5.00    1   $  0.10
    orchid:mary                31.00    3   $  0.62
    orchid:zhang                9.00    1   $  0.18
    rose:andy                   2.00    1   $  0.04
    rose:kelly                177.00  104   $  3.54
    rose:mary                  87.00   32   $  1.74
    rose:root                  26.00   12   $  0.52

    total                     337.00  154   $  6.74

Folgende Argumente können an pac(8) übergeben werden:

`-P`Drucker``

  Gibt an, welcher `Drucker` ausgewertet werden soll. Diese Option setzt voraus, dass für die `af`-Fähigkeit in `/etc/printcap` ein absoluter Pfad angegeben wurde.

`-c`

  Sortiert die Ausgabe nach den verursachten Kosten anstelle einer alphabetischen Sortierung der Benutzernamen.

`-m`

  Ignoriert den Rechnernamen in Verrechnungsdateien. Ist diese Option gesetzt, ist der Benutzer `smith` auf dem Rechner `alpha` mit dem Benutzer `smith` auf dem Rechner `gamma` identisch. Ist diese Option nicht gesetzt, handelt es sich um unterschiedliche Benutzer.

`-p`Preis``

  Berechnet die entstandenen Kosten aus dem `Preis` in Dollar pro Seite statt aus dem über die `pc`-Fähigkeit in `/etc/printcap` definierten Preis. In der Voreinstellung sind dies zwei Cent pro Seite. Sie können aber auch einen eigenen `Preis` in Form einer Gleitkommazahl angeben.

`-r`

  Die Sortierreihenfolge umkehren.

`-s`

  Die Verrechnungsdatei in einer neuen Datei aufsummieren und die originale Verrechnungsdatei zurücksetzen.

`name` `...`

  Verrechnungsinformationen nur für die angegebenen Benutzernamen ausgeben.

In der Voreinstellung gibt pac(8) aus, wieviele Seiten von welchem Benutzer auf welchem Rechner gedruckt wurden. Wenn Rechnernamen für Sie uninteressant sind (weil sich Benutzer beispielsweise auf jedem Rechner anmelden können), sollten Sie `pac -m` verwenden, um die folgende Ausgabe zu erhalten:

      Login               pages/feet   runs    price
    andy                        2.00    1   $  0.04
    kelly                     182.00  105   $  3.64
    mary                      118.00   35   $  2.36
    root                       26.00   12   $  0.52
    zhang                       9.00    1   $  0.18

    total                     337.00  154   $  6.74

Um den zu verrechnenden Betrag zu ermitteln, verwendet pac(8) die `pc`-Fähigkeit von `/etc/printcap` (Voreinstellung 200, dieser Wert entspricht 2 Cents). Geben Sie hier (als Hundertfaches des tatsächlichen Wertes) den Preis pro Seite an, den Sie verrechnen wollen. Sie können diesen Wert überschreiben, wenn Sie pac(8) mit der Option `-p` ausführen. Beachten Sie dabei aber, dass Sie in diesem Fall die Einheiten in Dollar angeben, und nicht als Hundertfaches des tatsächlichen Cent-Betrages. So steht

    # pac -p1.50

beispielsweise für einen Preis von einem Dollar und fünfzig Cent pro Seite.

Der Aufruf von `pac -s` führt schließlich dazu, dass die aufsummierten Informationen in einer eigenen Auswertedatei gespeichert werden. Diese hat den gleichen Namen wie die Verrechnungsdatei, es wird lediglich ein `_sum` an den Dateinamen angehängt. Danach wird die Verrechnungsdatei zurückgesetzt. Wenn Sie pac(8) erneut aufrufen, wird die Auswertedatei eingelesen, um die Startbeträge zu erhalten, alle weiteren Informationen stammen danach aus der normalen Verrechnungsdatei.

### 9.4.5.2. Wie kann man die Anzahl der gedruckten Seiten ermitteln?

Um die Druckernutzung auch nur annähernd genau verrechnen zu können, müssen Sie ermitteln, wieviel Papier ein Druckauftrag verbraucht. Die Bestimmung dieses Wertes ist das zentrale Problem, das Sie lösen müssen, wenn Sie Druckaufträge kostenpflichtig machen wollen.

Normaler Text stellt in der Regel kein Problem dar: Sie zählen dazu nur die Zeilen des Druckauftrages und dividieren diesen Wert durch die Anzahl der Zeilen pro Seite, die Ihr Drucker bietet. Allerdings dürfen Sie dabei nicht vergessen, dass gelöschte Zeichen (Backspaces) Zeilen überschreiben. Außerdem können sich lange logische Zeilen (im Druckauftrag) über mehrere physikalische Zeilen (am Ausdruck) erstrecken.

Der im Abschnitt lpf: Ein Textfilter vorgestellte Textfilter `lpf` berücksichtigt diese Besonderheiten. Wenn Sie einen eigenen Textfilter für die Verrechnung der Druckernutzung schreiben wollen, sollten Sie sich daher den Quellcode von `lpf` näher ansehen.

Aber was ist mit anderen Dateiformaten?

Für die DVI-nach-LaserJet- oder für die DVI-nach-PostScript-Konvertierung können Sie die Protokolldateien von `dvilj` oder `dvips` auslesen, um festzustellen, wieviele Seiten konvertiert wurden. Die gleiche Methode könnte auch mit anderen Dateitypen funktionieren.

Alle diese Methoden haben aber das Problem, dass ein Drucker möglicherweise nicht alle Seiten des Druckauftrages drucken kann. So könnte es etwa zu einem Papierstau kommen, der Toner könnte zu Ende gehen oder es könnte ein Druckerdefekt auftreten - trotzdem würden alle Seiten des Druckauftrages verrechnet werden.

Was kann man dagegen tun?

Es gibt nur eine einzige sichere Methode, um die Druckernutzung exakt zu bestimmen. Besorgen Sie sich einen Drucker, der das verbrauchte Papier protokolliert und verbinden Sie ihn über eine serielle oder eine Netzwerkverbindung. Nahezu alle PostScript-Drucker, aber auch viele andere Modelle und Druckertypen (beispielsweise Laserdrucker von Imagen) sind dazu in der Lage. Passen Sie die Filter für diese Drucker entsprechend an, damit diese nach jedem Druckauftrag die Anzahl der gedruckten Seiten ermitteln und verrechnen Sie Druckaufträge ausschließlich über diesen Wert. Danach müssen Sie sich um die Anzahl der gedruckten Zeilen oder um mögliche Druckerprobleme nie mehr kümmern.

Sie können aber auch großzügig sein und alle Ausdrucke kostenlos abgeben.

Zurück | Zum Anfang | Weiter
Grund-Konfiguration | Nach oben | Drucker verwenden

Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an <de-bsd-questions@de.FreeBSD.org>.
Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an <de-bsd-translators@de.FreeBSD.org>.