10.4. Geavanceerde printerinstallatie

WaarschuwingVanaf FreeBSD 8.0; zijn de apparaatknooppunten voor seriële poorten hernoemd van /dev/ttydN naar /dev/ttyuN. FreeBSD 7.X gebruikers moeten de volgende documentatie aanpassen naar aanleiding van deze wijzigingen.

Deze sectie behandelt het gebruik van filters om speciaal opgemaakte tekst en voorbladen af te drukken, via het netwerk af te drukken en printergebruik te beperken en statistieken bij te houden.

10.4.1. Filters

Hoewel LPD veel van het afdrukwerk afhandelt (netwerkverkeer, wachtrijafhandeling, toegangscontrole, enzovoort), wordt het echte werk door de filters gedaan. Filters zijn programma's die met een printer communiceren en inspelen op printerspecifieke eigenschappen. In de eenvoudige printeropzet is een filter geïnstalleerd voor platte tekst, een zeer eenvoudig filter dat met de meeste printers zou moeten werken (Tekstfilter installeren).

Om echter gebruik te maken van formaatomzetting, printeradministratie, printerspecifieke aanpassingen, enzovoort, is het nodig te weten hoe filters werken. Uiteindelijk is het de verantwoordelijkheid van het filter om deze zaken af te handelen. Het slechte nieuws is dat de beheerder in het merendeel van de gevallen het filter moet aanleveren. Het goede nieuws is dat veel filters algemeen beschikbaar zijn en als ze dat niet zijn, zijn ze vaak makkelijk te schrijven.

FreeBSD heeft een ingebouwd filter, /usr/libexec/lpr/lpf, die met veel printers werkt die platte tekst kunnen afdrukken. Het filter regelt backspace en tabs in bestanden en administreert printergebruik, maar dat is zo'n beetje alles wat dit filter doet. Er zijn ook diverse filters en filtercomponenten in de FreeBSD Portscollectie.

Hieronder wordt het volgende beschreven:

Opmerking: Een kopie van de scripts die hieronder worden beschreven, staan in de map /usr/share/examples/printing.

10.4.1.1. Hoe filters werken

Zoals eerder genoemd, is een filter een programma dat wordt uitgevoerd door LPD voor het afhandelen van het apparaatafhankelijke deel van de communicatie met een printer.

Als LPD een bestand wil afdrukken uit een afdrukopdracht, start het een filterprogramma. Het koppelt de standaard invoer van de filter aan het af te drukken bestand, de standaard uitvoer aan de printer en de standaard foutmelding aan het logboekbestand voor foutmeldingen (zoals opgegeven via de optie lf in /etc/printcap of standaard /dev/console).

Welk filter LPD start en de argumenten van het filter hangen af van wat er in het bestand /etc/printcap wordt opgegeven en de argumenten die de gebruiker geeft op de commandoregel van lpr(1). Als een gebruiker bijvoorbeeld lpr -t ingeeft, start LPD het filter troff, zoals wordt opgegeven via de optie tf voor de betreffende printer. Als een gebruiker platte tekst wilt afdrukken, dan wordt het filter if gestart (dit klopt bijna: zie Uitvoerfilters voor de details).

Er zijn drie soorten filters die in /etc/printcap kunnen worden opgegeven:

  • Het tekstfilter, dat in de LPD documentatie verwarrend genoeg input filter wordt genoemd, verwerkt het afdrukken van gewone tekst. Beschouw het als het standaardfilter. LPD verwacht dat elke printer standaard platte tekst kan afdrukken en het is de taak van het tekstfilter om er voor te zorgen dat backspaces, tabs en andere speciale karakters de printer niet in de war sturen. In een omgeving waar moet worden bijgehouden hoeveel er wordt afgedrukt, moet het tekstfilter ook administreren hoeveel pagina's er zijn afgedrukt. Dit gaat meestal door het aantal afgedrukte regels te tellen en dit te vergelijken met het aantal regels per pagina dat door de printer wordt ondersteund. Het tekstfilter wordt aangeroepen met de volgende lijst argumenten:

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

    met

    -c

    wordt gebruikt als de afdrukopdracht is gegeven met lpr -l

    width

    is de waarde van de optie pw (page width: paginabreedte), zoals opgegeven in /etc/printcap, standaard 132

    length

    is de waarde van de optie pl (page length: paginalengte), standaard 66

    indent

    geeft aan hoeveel wordt ingesprongen door lpr -i, standaard 0

    login

    de gebruikersnaam van de gebruiker die de afdrukopdracht gaf

    host

    de hostnaam waar de afdrukopdracht gegeven is

    acct-file

    de naam van het administratiebestand zoals opgegeven via de optie af.

  • Een conversiefilter converteert een specifiek bestandsformaat naar een formaat dat een printer begrijpt. Bijvoorbeeld: ditroff typesettinggegevens kunnen niet direct worden afgedrukt, maar er bestaat wel een conversiefilter om ditroff-gegevens te converteren naar een formaat dat een printer kan verteren en afdrukken. Dit wordt in Conversiefilters beschreven. Conversiefilters zijn ook nodig om printergebruik te administreren, mocht dat nodig zijn. Conversiefilters worden met de volgende argumenten aangeroepen:

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

    Hier is pixel-width de waarde van de optie px (standaard 0) en pixel-height is de waarde van de optie py (standaard 0).

  • Het uitvoerfilter wordt alleen gebruikt als er geen tekstfilter is of als er voorbladen worden afgedrukt. De ervaring leert dat uitvoerfilters zelden worden gebruikt. In sectie Uitvoerfilters worden ze beschreven. Er zijn slechts twee argumenten die aan een uitvoerfilter worden meegegeven:

    filter-name -w width -l length

    Deze zijn identiek aan de argumenten -w en -l van het tekstfilter.

Filters moeten afsluiten met de volgende waarde:

exit 0

Als het filter een bestand succesvol heeft afgedrukt.

exit 1

Als het filter niet geslaagd is om een bestand af te drukken, maar wil dat LPD het nogmaals probeert. LPD herstart het filter als die afsluit met deze status.

exit 2

Als het filter niet geslaagd is om een bestand af te drukken, maar niet wil dat LPD het nogmaals probeert. LPD verwijdert het bestand uit de wachtrij.

Het tekstfilter dat bij FreeBSD wordt geleverd, /usr/libexec/lpr/lpf, benut de argumenten voor paginabreedte en -lengte om te bepalen wanneer een nieuwe pagina moet worden begonnen en om het printergebruik bij te houden. Het gebruikt de argumenten voor login, host en administratiebestand om accountingregels aan te maken.

Controleer bij het zoeken naar filters of ze LPD-compatibel zijn. Zo ja, dan ondersteunen ze de argumenten zoals hierboven beschreven. Zorg bij het zelf schrijven van filters voor algemeen gebruik dat ze dezelfde argumenten en exitcodes ondersteunen.

10.4.1.2. Platte tekst op PostScript®-printers afdrukken

Als een computer en PostScript (of andere op taal gebaseerde) printer maar één gebruiker hebben die belooft nooit platte tekst naar de printer te sturen of programma's te gebruiken die dat doen, dan is dit onderdeel overbodig.

Als gebruikers zowel PostScript als platte tekst naar een printer willen sturen, dan is het aan te raden de printerinstellingen hierop aan te passen. Hiervoor moet het tekstfilter bij elke nieuwe opdracht bepalen of het om platte tekst of PostScript gaat. Alle PostScript-opdrachten beginnen met %! (raadpleeg de printerhandleiding voor andere printertalen). Als dit de eerste twee karakters zijn van een opdracht is het PostScript en kan de rest van een opdracht direct doorgestuurd worden. Is dit niet het geval, dan moet de filter de tekst omzetten in PostScript en het resultaat afdrukken.

Hoe gaat dat werken?

Voor seriële printers kan het meest eenvoudig lprps geïnstalleerd worden. lprps is een PostScript-afdrukfilter die tweewegcommunicatie met een printer heeft. Het werkt het statusbestand van een printer bij met uitgebreide informatie afkomstig van een printer, zodat gebruikers en beheerders precies kunnen zien wat de status van een printer is (zoals: “toner bijna op” of “papier vastgelopen”). Maar belangrijker, het omvat het programma psif dat bepaalt of een binnenkomende opdracht platte tekst is en textps (dat ook geleverd wordt met lprps) om opdrachten om te zetten naar PostScript. Vervolgens wordt een opdracht met lprps naar een printer gestuurd.

lprps is onderdeel van de FreeBSD Portscollectie (zie De Portscollectie). U kunt één van de ports print/lprps-a4 of print-lprps-letter installeren afhankelijk van de gebruikte papiermaat. Nadat lprps is geïnstalleerd moet de installatielocatie ervan aan psif worden doorgeven dat onderdeel is van lprps. Als lprps is geïnstalleerd via de Portscollectie, gebruik dan het volgende voor de seriële PostScript-printer in /etc/printcap:

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

Ook moet de optie rw worden opgeven, die LPD vertelt om een printer in lezen/schrijvenmodus te openen.

Als een parallelle PostScript-printer wordt ingesteld (en dus geen tweewegcommunicatie toegepast kan worden met de printer, zoals vereist door lprps), dan kan het volgende shellscript gebruikt worden als tekstfilter:

#!/bin/sh
#
#  psif - Druk PostScript of platte tekst af op een PostScript
#  printer. Script versie; NIET de versie die wordt geleverd bij lprps
#  Geïnstalleerd in /usr/local/libexec/psif
#

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

if [ "$first_two_chars" = "%!" ]; then
    #
    #  PostScript opdracht, afdrukken.
    #
    echo "$first_line" && cat && printf "\004" && exit 0
    exit 2
else
    #
    #  Platte tekst, converteren en dan afdrukken.
    #
    ( echo "$first_line"; cat ) | /usr/local/bin/textps && printf "\004" && exit 0
    exit 2
fi

In bovenstaand script is textps een programma dat geïnstalleerd is om platte tekst om te zetten naar PostScript. Elk tekst-naar-PostScript programma volstaat. De FreeBSD Portscollectie (zie De Portscollectie) bevat een uitgebreid tekst-naar-PostScript-programma, a2ps, dat wellicht handig is om te gebruiken.

10.4.1.3. PostScript simuleren op niet-PostScript-printers

PostScript is de facto de standaard voor op hoge kwaliteit typesetten en afdrukken. PostScript is echter een dure standaard. Gelukkig heeft Aladdin Enterprises een gratis PostScript-kloon, Ghostscript, die werkt onder FreeBSD. Ghostscript kan de meeste PostScript-bestanden lezen en de pagina's op verschillende soorten apparaten weergeven, waaronder veel niet-PostScript-printers. Door Ghostscript te installeren en een printer gebruik te laten maken van een speciaal tekstfilter voor uw printer, kan uw niet-PostScript-printer zich gedragen als een echte PostScript-printer.

Ghostscript is beschikbaar via de FreeBSD Portscollectie, vele versies zijn beschikbaar, de meest gebruikte versie is print/ghostscript-gpl.

Om PostScript te simuleren moet een tekstfilter detecteren of het een PostScript-bestand aan het afdrukken is. Zo niet, dan stuurt het filter het bestand direct naar een printer, anders gebruikt het filter Ghostscript om het bestand om te zetten naar een formaat dat door een printer wordt begrepen.

Een voorbeeld: het volgende script is een tekstfilter voor Hewlett Packard DeskJet 500 printers. Voor andere printers moet het argument -sDEVICE voor het commando gs (Ghostscript) vervangen worden. (Met gs -h wordt een lijst met apparaten getoond worden die de huidige installatie van Ghostscript ondersteunt.)

#!/bin/sh
#
#  ifhp - Druk Ghostscript-gesimuleerd PostScript af op een DeskJet
#  500.  Geïnstalleerd in /usr/local/libexec/ifhp

#
#  Behandel LF als CR+LF (om een "trapeffect" op HP/PCL
#  printer te voorkomen):
#
printf "\033&k2G" || exit 2

#
#  Lees de eerste twee karakters van het bestand
#
IFS="" read -r first_line
first_two_chars=`expr "$first_line" : '\(..\)'`

if [ "$first_two_chars" = "%!" ]; then
    #
    #  Het is PostScript. Gebruik Ghostscript om te converteren
    #  en druk het af.
    #
    /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \
        -sOutputFile=- - && exit 0
else
    #
    #  Platte tekst of HP/PCL, dus direct afdrukken;  druk een
    #  pagina-einde af om de laatste pagina te ejecteren.
    #
    echo "$first_line" && cat && printf "\033&l0H" &&
exit 0
fi

exit 2

Tot slot moet LPD op de hoogte gebracht worden van het filter via de optie if:

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

Dat is alles. Nu kan lpr platte.tekst en lpr watdanook.ps ingevoerd worden en beiden worden juist afgedrukt.

10.4.1.4. Conversiefilters

Na de eenvoudige installatie, zoals beschreven in Eenvoudige printerinstallatie, te hebben voltooid, is het waarschijnlijk wenselijk om conversiefilters te installeren voor favoriete bestandsformaten (naast platte ASCII-tekst).

10.4.1.4.1. Waarom conversiefilters installeren?

Conversiefilters maken het afdrukken van verschillende bestanden eenvoudig. Stel dat veel gebruik gemaakt wordt van het tekstverwerkingsprogramma TeX en een PostScript printer. Elke keer als door TeX een DVI-bestand wordt gegenereerd, kan dat niet direct afgedrukt worden. Het DVI-bestand moet omgezet worden naar PostScript. De te geven opdrachten zijn de volgende:

% dvips zeewieranalyse.dvi
% lpr zeewieranalyse.ps

Na installatie van een conversiefilter voor DVI-bestanden kan deze handmatige conversie overgeslagen worden door LPD de conversie te laten uitvoeren. Elke keer als een DVI-bestand wordt afgedrukt, hoeft alleen de volgende opdracht gegeven te worden:

% lpr -d zeewieranalyse.dvi

LPD voert de DVI-bestandsconversie uit door -d te geven. In Opties voor opmaak en conversie staat een lijst van conversie-opties.

Voor elke conversie-optie moet een conversiefilter geïnstalleerd worden en moet in /etc/printcap de locatie worden opgegeven. Een conversiefilter is als het tekstfilter voor de eenvoudige printerinstallatie (Tekstfilter installeren), behalve dat in plaats van platte tekst af te drukken, het conversiefilter het bestand converteert naar een formaat dat een printer begrijpt.

10.4.1.4.2. Welke conversiefilters installeren?

Installeer de conversiefilters die nodig zijn. Als veel DVI-bestanden worden afgedrukt, dan is het handig een DVI-filter te installeren. Als veel troff wordt afgedrukt, dan is het waarschijnlijk handig een troff-filter te installeren.

De volgende tabel geeft een samenvatting van filters waarmee LPD kan werken, hoe ze in /etc/printcap kunnen worden aangeroepen en hoe ze met lpr kunnen worden aangeroepen:

Bestandsformaat /etc/printcap optie lpr optie
cifplot cf -c
DVI df -d
plot gf -g
ditroff nf -n
FORTRAN-tekst rf -f
troff tf -f
raster vf -v
platte tekst if geen, -p, of -l

In het voorbeeld waarbij lpr -d wordt gebruikt, moet voor de printer een optie df gedefinieerd staan in /etc/printcap.

Ondanks wat anderen mogelijk beweren, zijn formaten als FORTRAN-tekst en plot waarschijnlijk verouderd. Dit biedt de mogelijkheid een nieuwe betekenis te geven aan deze opties door zelf een filter te installeren. Stel dat direct Printerleaf-bestanden afgedrukt moeten worden (bestanden van het bureaubladpublicatieprogramma Interleaf), maar nooit plotbestanden worden afgedrukt. Dan kan een Printerleaf-conversiefilter geïnstalleerd worden onder de optie gf en gebruikers kunnen geïnstrueerd worden om lpr -g te gebruiken om Printerleaf-bestanden af te drukken.

10.4.1.4.3. Conversiefilters installeren

Aangezien conversiefilters programma's zijn die niet onder de FreeBSD-basisinstallatie vallen, kunnen ze het best onder /usr/local geplaatst worden. De map /usr/local/libexec is een veelgebruikte locatie, omdat hier programma's te vinden zijn die alleen door LPD gebruikt worden. Gewone gebruikers hoeven ze nooit te gebruiken.

Om een conversiefilter te activeren, moet de bestandslocatie onder de juiste optie voor de betreffende printer in /etc/printcap opgegeven worden.

In het onderstaande voorbeeld wordt het DVI-conversiefilter toegevoegd onder de sectie van de printer bamboo. Hieronder staat opnieuw het voorbeeldbestand /etc/printcap, nu met de nieuwe optie df voor de printer bamboo:

#
#  /etc/printcap voor host rose - df-filter voor bamboo toegevoegd
#
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/ttyu5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:

Het DVI-filter is een shellscript met de naam /usr/local/libexec/psdf. Het script ziet er als volgt uit:

#!/bin/sh
#
#  psdf - DVI naar PostScript afdrukfilter
#  Geïnstalleerd in /usr/local/libexec/psdf
#
# Aangeroepen door lpd wanneer een gebruiker lpr -d uitvoert
#
exec /usr/local/bin/dvips -f | /usr/local/libexec/lprps "$@"

Dit script roept dvips in filtermodus aan (het -f argument) op de standaard uitvoer, de af te drukken opdracht. Vervolgens start het PostScript afdrukfilter lprps (zie Platte tekst op PostScript-printers afdrukken) met de argumenten die LPD aan het script doorgeeft. lprps gebruikt deze argumenten om de afgedrukte pagina's te administreren.

10.4.1.4.4. Meer voorbeelden van conversiefilters

Er is geen vaste procedure om conversiefilters te installeren, er worden in deze sectie wat werkende voorbeelden gegeven. Gebruik deze als hulp bij het zelf maken van filters. Gebruik ze zonder aanpassingen indien mogelijk.

Dit voorbeeldscript is een raster (eigenlijk een GIF-bestand) conversiefilter voor een HP LaserJet III-Si printer:

#!/bin/sh
#
#  hpvf - Converteer GIF-bestanden naar HP/PCL, druk vervolgens af
#  Geïnstalleerd in /usr/local/libexec/hpvf

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

Het script converteert achtereenvolgens het GIF-bestand naar een PNM-bestand (portable anymap), een PGM-bestand (portable graymap), een PBM-bestand (portable bitmap) en tenslotte naar LaserJet/PCL formaat.

Een /etc/printcap bestand dat bovenstaand filter gebruikt ziet er als volgt uit:

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

Het volgende script is een conversiefilter voor troff-gegevens afkomstig van het groff-typesettingsysteem voor de PostScript-printer bamboo:

#!/bin/sh
#
#  pstf - Converteert groff's troffgegevens naar PS, drukt vervolgens af.
#  Geïnstalleerd in /usr/local/libexec/pstf
#
exec grops | /usr/local/libexec/lprps "$@"

Bovenstaande script maakt eveneens gebruik van lprps om de communicatie met een printer af te handelen. Als een printer op een parallelle poort is aangesloten, ziet het er als volgt uit:

#!/bin/sh
#
#  pstf - Converteert groff's troff naar PS, drukt vervolgens af.
#  Geïnstalleerd in /usr/local/libexec/pstf
#
exec grops

Dat is alles. In /etc/printcap moet het volgende toegevoegd worden om het filter beschikbaar te maken:

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

Hieronder een voorbeeld waarvan FORTRAN-programmeurs waarschijnlijk tranen in hun ogen krijgen: een FORTRAN-tekstfilter voor een willekeurige printer die in staat is platte tekst af te drukken. Het filter wordt actief gemaakt voor teak:

#!/bin/sh
#
# hprf - FORTRAN tekstfilter voor LaserJet 3si:
# Geïnstalleerd in /usr/local/libexec/hprf
#

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

De onderstaande regel wordt toegevoegd aan /etc/printcap voor de printer teak om het filter beschikbaar te maken:

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

Het laatste voorbeeld is wellicht complexer. Er wordt een DVI-filter toegevoegd voor de eerder genoemde LaserJet printer teak. Eerst het makkelijke gedeelte: in /etc/printcap wordt de locatie van het DVI-filter opgegeven:

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

Nu het moeilijke gedeelte: het schrijven van het filter. Daarvoor is een DVI-naar-LaserJet/PCL conversieprogramma nodig. De FreeBSD Portscollectie (zie Portscollectie) heeft er een: print/dvi2xx. Door deze port te installeren komt het programma dat nodig is beschikbaar, dvilj2p, waarmee DVI geconverteerd kan worden naar LaserJet IIp-, LaserJet III- en LaserJet 2000-formaten.

Het hulpprogramma dvilj2p maakt het filter hpdf redelijk complex, omdat dvilj2p niet van de standaard invoer kan lezen. Het wil werken met een bestandsnaam. Nog lastiger is dat de bestandsnaam moet eindigen op .dvi, zodat moeilijk gebruik gemaakt kan worden van /dev/fd/0 als standaard. Dit probleem kan omzeild worden door een (symbolische) koppeling aan te maken van een tijdelijk bestand (eindigend op .dvi) naar /dev/fd/0. Hiermee wordt dvilj2p gedwongen van de standaard invoer te lezen.

De enige andere hobbel die genomen moet worden, is dat /tmp niet gebruikt kan worden als tijdelijke koppeling. Symbolische koppelingen zijn eigendom van de gebruiker en groep bin. Het filter wordt uitgevoerd door de gebruiker daemon. De map /tmp heeft het sticky-bit aan staan. Het filter kan de koppeling wel aanmaken, maar het is niet mogelijk de koppeling te verwijderen als de opdracht is uitgevoerd, omdat de koppeling eigendom is van een andere gebruiker.

In plaats hiervan maakt het filter een symbolische koppeling aan in de huidige werkmap, de wachtrijmap (zoals opgegeven in de optie sd in /etc/printcap). Dit is een perfecte plaats voor filters om hun werk te doen, zeker gezien er (soms) meer vrije schijfruimte is in de wachtrijmap dan onder /tmp.

Dit is het uiteindelijke filter:

#!/bin/sh
#
#  hpdf - Druk DVI-gegevens af op een HP/PCL printer
#  Geïnstalleerd in /usr/local/libexec/hpdf

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

#
#  Definieer een functie om tijdelijke bestanden op te ruimen. Deze
#  staan in de huidige map; de wachtrijmap voor de printer.
#
cleanup() {
   rm -f hpdf$$.dvi
}

#
#  Definieer een functie om fatale fouten te verwerken: geef de
#  opgegeven boodschap weer en sluit af met 2. Afsluiten met 2 vertelt
#  LPD niet nog eens te proberen de afdrukopdracht af te drukken.
#
fatal() {
    echo "$@" 1>&2
    cleanup
    exit 2
}

#
#  Als de gebruiker de opdracht annuleert, stuurt LPD een SIGINT, dus
#  ondervang SIGINT (en enkele andere signalen) om onze rommel op te
#  ruimen.
#
trap cleanup 1 2 15

#
#  Voor de zekerheid bestaande tijdelijke bestanden opruimen
#
cleanup

#
#  Koppel het DVI-invoerbestand aan de standaard invoer (het af te
#  drukken bestand).
#
ln -s /dev/fd/0 hpdf$$.dvi || fatal "Cannot symlink /dev/fd/0"

#
#  Maak LF = CR+LF
#
printf "\033&k2G" || fatal "Cannot initialize printer"

#
#  Converteer en druk af.  De retourneerwaarde van dvilj2p lijkt niet
#  betrouwbaar, dus negeren we het.
#
dvilj2p -M1 -q -e- dfhp$$.dvi

#
#  Opruimen en afsluiten
#
cleanup
exit 0

10.4.1.4.5. Automatische conversie: een alternatief voor conversiefilters

Al deze conversiefilters bieden vele mogelijkheden voor afdrukomgevingen, maar dwingen de gebruiker aan te geven (op de lpr(1) commandoregel) welk filter gebruikt moet worden. Als gebruikers niet zo vaardig zijn in het gebruik van computers, wordt het al snel vervelend steeds aan te moeten geven welk filter gebruikt moet worden. Vervelender is echter wanneer een gebruiker een verkeerd filter gebruikt voor een bepaald bestandsformaat. Het resultaat kan zijn dat een printer honderden pagina's papier uitspuugt.

In plaats van het installeren van conversiefilters, is het te proberen om het (standaard) tekstfilter het bestandstype van het af te drukken bestand te laten detecteren en dan automatisch het juiste conversiefilter aan te laten roepen. Programma's als file kunnen hierbij handig zijn. Voor sommige bestandsformaten kan het moeilijk zijn de verschillen te ontdekken en voor deze bestanden kan alsnog een conversiefilter beschikbaar worden gesteld.

De FreeBSD Portscollectie heeft een tekstfilter dat automatisch converteert genaamd apsfilter (print/apsfilter). Het detecteert platte tekst, PostScript en DVI-bestanden, voert de juiste conversie uit en druk de bestanden af.

10.4.1.5. Uitvoerfilters

Het wachtrijsysteem LPD ondersteunt een ander type filter waar nog geen aandacht aan is besteed: een uitvoerfilter. Een uitvoerfilter is bedoeld om alleen platte tekst af te drukken, net als een tekstfilter, maar met veel vereenvoudigingen. Wanneer een uitvoerfilter wordt gebruikt, maar geen tekstfilter, dan:

  • start LPD een uitvoerfilter voor de gehele opdracht, in plaats van voor elk bestand in de opdracht;

  • biedt LPD het uitvoerfilter niet de voorziening van het identificeren van het begin of eind van de bestanden in de afdrukopdracht;

  • stuurt LPD de gebruikersnaam en de hostnaam niet door aan het filter. Het is dus niet bedoeld om een afdrukadministratie bij te houden. In feite zijn er maar twee argumenten:

    filter-name -wwidth -llength

    Hierbij is width afkomstig van de optie pw en length afkomstig van de optie pl voor de betreffende printer.

De eenvoud van een uitvoerfilter is verleidelijk. Als elk bestand in een afdrukopdracht op een nieuwe pagina moet beginnen, is een uitvoerfilter niet geschikt. In dat geval dient een tekstfilter (ook wel invoerfilter) gebruikt te worden (zie Tekstfilter installeren. Verder is een uitvoerfilter eigenlijk veel ingewikkelder, omdat de te verwerken bytestroom gecontroleerd moet worden op speciale tekens en steeds signalen naar zichzelf moet sturen in opdracht van LPD.

Een uitvoerfilter is noodzakelijk als voorbladen gewenst zijn en het nodig is om escape-reeksen of andere initialisatietekens te sturen voor het afdrukken van het voorblad. Maar het is tevens nutteloos als het voorblad voor rekening van de afkomstige gebruiker moet komen, aangezien LPD geen gebruiker of hostinformatie naar het uitvoerfilter stuurt.

Op een enkele printer staat LPD het gebruik van zowel een uitvoerfilter als van een tekst of andere filter toe. In deze gevallen start LPD het uitvoerfilter alleen voor het afdrukken van het voorblad (zie Voorbladen). LPD verwacht vervolgens van het uitvoerfilter dat deze zichzelf stopt door twee bytes naar het filter te sturen: ASCII 031 gevolgd door ASCII 001. Als een uitvoerfilter deze twee bytes ziet (031, 001), moet die stoppen door een SIGSTOP naar zichzelf te sturen. Als LPD klaar is met het uitvoeren van alle andere filters, dan herstart deze het uitvoerfilter door er een SIGCONT naar toe te sturen.

Als er wel een uitvoerfilter, maar geen tekstfilter is en LPD is niet bezig met het verwerken van een opdracht met platte tekst, dan gebruikt LPD het uitvoerfilter voor het afdrukken van de opdracht. Zoals eerder vermeld, drukt het uitvoerfilter elk bestand van de opdracht achter elkaar af zonder pagina-einden of andere signalen voor paginavoortgang. Dit is waarschijnlijk niet gewenst. In bijna alle gevallen is een tekstfilter nodig.

Het programma lpf, dat eerder geïntoduceerd is als tekstfilter, kan ook worden uitgevoerd als uitvoerfilter. Als een ad-hoc uitvoerfilter nodig is, maar het schrijven van de bytedetectie en signaalverzending code niet wenselijk is, dan is lpf het proberen waard. lpf kan ook opgenomen worden in een shellscript om initialisatiecode af te handelen die eventueel nodig is voor een printer.

10.4.1.6. lpf: een tekstfilter

Het programma /usr/libexec/lpr/lpf uit de gecompileerde FreeBSD-distributie is een tekstfilter (invoerfilter) die uitvoer kan inspringen (een opdracht gegeven met lpr -i), karakters onveranderd kan doorlaten (een opdracht gegeven met lpr -l), de printpositie voor backspaces en tabs in de opdracht kan aanpassen en afgedrukte pagina's kan administreren. Het kan ook functioneren als uitvoerfilter.

Het filter lpf is geschikt voor vele afdrukomgevingen. Hoewel het zelf niet in staat is initialisatiesequenties naar een printer te sturen, is het vrij eenvoudig om een shellscript te schrijven dat de initialisatie doet en vervolgens lpf aanroept.

Als lpf afgedrukte pagina's moet administreren, is het nodig om de juiste waarden in te vullen voor de opties pw en pl in het bestand /etc/printcap. Deze waarden worden gebruikt om te bepalen hoeveel tekst er op een pagina past en hoeveel pagina's er in een afdrukopdracht zijn afgedrukt. Zie Printergebruik administreren voor meer informatie.

10.4.2. Voorbladen

Als er veel gebruikers zijn die allemaal verschillende printers gebruiken, dan is het te overwegen gebruik te maken van voorbladen als noodzakelijk kwaad.

Voorbladen, in het Engels ook wel bekend als banner of burst pagina's, identificeren wie een bepaalde opdracht heeft afgedrukt. Ze worden meestal bedrukt met grote, dikgedrukte letters, eventueel met een decoratieve rand, zodat ze in een stapel afdrukken opvallen tussen de afgedrukte documenten. Ze maken het gebruikers mogelijk hun afdrukopdracht snel te vinden. Het nadeel van het gebruik van voorbladen is dat er een extra blad moet worden afgedrukt voor elke opdracht, waarmee hun nut niet langer duurt dan een paar minuten. Uiteindelijk belanden ze in een papierbak of afvalberg. Voorbladen gaan vooraf aan elke opdracht, niet aan elk bestand in een opdracht, waardoor de verspilling beperkt blijft.

Het LPD-systeem kan automatisch voorbladen afdrukken als een printer direct platte tekst kan afdrukken. In geval van een PostScript-printer, is het nodig een extern programma aan te roepen om een voorblad te genereren (zie Voorbladen op PostScript-printers.

10.4.2.1. Voorbladen afdrukken

In de sectie Eenvoudige printerinstallatie is het afdrukken van voorbladen uitgeschakeld door de optie sh (“suppress header”) in het bestand /etc/printcap op te geven. Om wel voorbladen af te drukken, hoeft alleen de optie sh verwijderd te worden.

Dit klinkt wat al te makkelijk, of niet?

Dat klopt. Het kan nodig zijn een uitvoerfilter op te geven die initialisatiestrings naar een printer stuurt. Hier is een voorbeeld uitvoerfilter voor HP PCL-compatible printers:

#!/bin/sh
#
#  hpof - Uitvoerfilter voor HP PCL-compatible printers
#  Geïnstalleerd in /usr/local/libexec/hpof

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

Geef de locatie van het uitvoerfilter op met de optie of. Zie Uitvoerfilters voor meer informatie.

Hier is een voorbeeldbestand /etc/printcap voor de printer teak die eerder is geïntroduceerd;. Het afdrukken van voorbladen is geactiveerd en bovenstaande uitvoerfilter is toegevoegd:

#
#  /etc/printcap voor host orchid
#
teak|hp|laserjet|HP 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:

Als gebruikers nu een opdracht sturen naar teak, wordt er bij elke opdracht een voorblad afgedrukt. Als gebruikers liever willen zoeken naar hun afdrukken, dan kunnen ze de voorbladen onderdrukken door de opdracht te geven met het commando lpr -h. Zie Voorbladopties voor meer opties voor lpr(1).

Opmerking: LPD drukt een karakter voor pagina-einde af na elk voorblad. Als een printer een ander teken of sequentie gebruikt voor het beëindigen van een pagina, dan kan dit opgeven worden met de optie ff in /etc/printcap.

10.4.2.2. Voorbladen beheren

Door het afdrukken van voorbladen aan te zetten, produceert LPD een lang voorblad waarop in grote letters de gebruiker, host en opdracht te lezen zijn. Hier volgt een voorbeeld (kelly heeft de opdracht “outline” afgedrukt vanaf host rose):

      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 geeft een paginabegin na deze tekst, zodat de opdracht op een nieuwe pagina begint (tenzij de optie sf (suppress form feeds, “onderdruk paginabegin”) is toegevoegd bij de desbetreffende printer in /etc/printcap).

Als dit wenselijk is, kan LPD ook een korte tekst op het voorblad afdrukken; geef hiervoor de optie sb (short banner, “kort voorblad”) op in het bestand /etc/printcap. Het voorblad ziet er dan als volgt uit:

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

Standaard drukt LPD het voorblad als eerste af en vervolgens de opdracht. Om dat om te keren, moet de optie hl (header last, “voorblad laatst”) in /etc/printcap worden opgeven.

10.4.2.3. Voorbladen administreren

Het gebruik van LPD's ingebouwde voorbladen dwingt een bepaald paradigma af wat betreft het administreren van printergebruik: voorbladen moeten gratis zijn.

Waarom?

Omdat het uitvoerfilter het enige externe programma is dat controle heeft als het voorblad afgedrukt wordt dat het gebruik zou kunnen administreren. Het heeft echter geen beschikking over informatie over gebruiker of host of een administratiebestand. Het heeft dus geen idee wie voor het gebruik moet worden belast. Het volstaat ook niet om gewoon “het aantal pagina's met één op te hogen” door het tekstfilter of een van de conversiefilters (dat wel beschikt over gebruiker- en hostinformatie) te veranderen, omdat gebruikers het afdrukken van een voorblad kunnen onderdrukken met lpr -h. Ze worden dan aangeslagen voor voorbladen die niet zijn afgedrukt. Milieubewuste gebruikers gebruiken vast lpr -h, maar dit kan niet worden afgedwongen.

Het is ook niet voldoende om elk filter zijn eigen voorblad te laten genereren (om zo het gebruik te kunnen administreren). Als gebruikers het afdrukken van voorbladen willen onderdrukken met lpr -h, krijgen ze toch een voorblad en worden er ook voor belast, aangezien LPD geen kennis over de optie -h doorgeeft aan de filters.

Wat zijn dan de mogelijkheden?

  • Accepteer het paradigma van LPD en maak voorbladen gratis;

  • Installeer een alternatief voor LPD, zoals LPRng. In Alternatieven voor het standaard wachtrijsysteem staat meer over andere afdruksoftware die in plaats van LPD geïnstalleerd kan worden;

  • Schrijf een slim uitvoerfilter. Gewoonlijk is een uitvoerfilter bedoeld om niet meer te doen dan het initialiseren van een printer of wat eenvoudige karakterconversie. Het is geschikt voor voorbladen en opdrachten met platte tekst (als er een tekstfilter is). Maar als er een tekstfilter is voor opdrachten met platte tekst, dan start LPD het uitvoerfilter alleen voor voorbladen. Het uitvoerfilter kan dan het voorblad dat LPD genereert analyseren om te bepalen welke gebruiker en host belast moeten worden voor het afdrukken van het voorblad. Het enige probleem is dat het uitvoerfilter nog steeds niet weet in welk bestand het gebruik moet worden bijgehouden (de naam van het bestand opgegeven in de af wordt niet meegegeven), maar als een bekend bestand gebruikt wordt, kan dit in het uitvoerfilter worden opgeven. Om het parsen af te handelen kan gebruik gemaakt worden van de optie sh (short header, “kort voorblad”) in /etc/printcap. Dit kan echter wat omslachtig zijn en gebruikers waarderen zeker de meer gulle systeembeheerder die voorbladen gratis maakt.

10.4.2.4. Voorbladen op PostScript-printers

Zoals hierboven beschreven, kan LPD een voorblad in platte tekst genereren, dat geschikt is voor de meeste printers. Natuurlijk kan PostScript platte tekst niet direct afdrukken, zodat de voorbladfunctie van LPD nutteloos is.

Een voor de hand liggende manier om voorbladen te krijgen, is elk conversiefilter en tekstfilter zijn eigen voorblad te laten genereren. De filters moeten gebruik maken van de argumenten gebruiker en host om een geschikt voorblad te genereren. Het nadeel van deze methode is dat gebruikers altijd een voorblad krijgen, ook wanneer zij een opdracht geven met lpr -h.

Deze methode wordt nader beschreven. Het volgende script heeft drie argumenten (gebruikersnaam, hostnaam en de naam van de opdracht) en maakt een eenvoudig PostScript-voorblad:

#!/bin/sh
#
#  make-ps-header - genereer een PostScript-voorblad op stdout
#  Geïnstalleerd in /usr/local/libexec/make-ps-header
#

#
#  Dit zijn PostScript-eenheden (72 in een inch). Pas dit aan voor A4
#  of het gebruikte formaat:
#
page_width=612
page_height=792
border=72

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

#
#  Bewaar deze, voornamelijk voor de leesbaarheid in de PostScript-code.
#
user=$1
host=$2
job=$3
date=`date`

#
#  Stuur de PostScript-code naar stdout.
#
exec cat <<EOF
%!PS

%
%  Vermijd conflicten met de opdracht van de gebruiker die volgt.
%
save

%
%  Maak een dikke, onaangename border in de marge van het papier.
%
$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

%
%  Toon de gebruikersnaam duidelijk, groot en prominent
%
/Helvetica-Bold findfont 64 scalefont setfont
$page_width ($user) stringwidth pop sub 2 div $page_height 200 sub moveto
($user) show

%
%  Nu volgen de saaie bijzonderheden
%
/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

%
% Dat is alles
%
restore
showpage
EOF

Nu kan zowel het conversiefilter als het tekstfilter dit script aanroepen om eerst een voorblad te genereren en vervolgens de opdracht van de gebruiker af te drukken. Hier volgt het eerder gebruikte DVI-conversieprogramma, aangepast om een voorblad te maken:

#!/bin/sh
#
#  psdf - DVI naar PostScript printfilter
#  Geïnstalleerd in /usr/local/libexec/psdf
#
#  Aangeroepen door lpd, wanneer de gebruiker lpr -d uitvoert
#

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

Merk op hoe het filter eerst de argumentenlijst moet nagaan om te bepalen wat de gebruikers- en hostnaam zijn. Dit is gelijk voor de andere conversiefilters. Het tekstfilter heeft echter een andere verzameling argumenten (zie Hoe filters werken).

Zoals eerder is beschreven, is het in bovenstaande opzet, hoewel deze simpel is, niet mogelijk “voorbladen te onderdrukken” (de optie -h in lpr). Als gebruikers een boom willen sparen (of een paar centen bij betaalde voorbladen) dan is dit dus niet mogelijk, aangezien elk filter een voorblad afdrukt voor iedere opdracht.

Om gebruikers in staat te stellen per opdracht voorbladen te onderdrukken, moet gebruik gemaakt worden van de truc uit Voorbladen administreren: schrijf een uitvoerfilter dat het door LPD gegenereerde voorblad inleest en een PostScript-versie genereert. Als de gebruiker de opdracht geeft met lpr -h, dan genereert LPD geen voorblad en het uitvoerfilter ook niet. Anders leest het uitvoerfilter de tekst van LPD in en stuurt een geschikt voorblad in PostScript naar de printer.

Voor een PostScript-printer op een seriële lijn kan gebruik gemaakt worden van lprps, dat met een uitvoerfilter wordt geleverd en het bovenstaande kan doen. Voorbladen worden door psof niet geteld.

10.4.3. Afdrukken via het netwerk

FreeBSD ondersteunt afdrukken via het netwerk: het sturen van opdrachten naar printers op afstand. Afdrukken via een netwerk betekent over het algemeen twee verschillende dingen:

10.4.3.1. Printers geïnstalleerd op andere hosts

Het wachtrijsysteem LPD heeft een ingebouwde mogelijkheid om opdrachten naar andere hosts te sturen die ook LPD draaien (of een systeem dat compatibel is met LPD). Deze eigenschap maakt het mogelijk om een printer op een host te installeren en deze toegankelijk te maken voor andere hosts. Het werkt ook met printers die over een netwerkinterface beschikken en het LPD-protocol begrijpen.

Om dit soort afdrukken op afstand mogelijk te maken, moet een printer eerst op een host geïnstalleerd worden, de printerhost, door de printerinstallatie te volgen als beschreven in Eenvoudige printerinstallatie. Stel desgewenst de printer in voor geavanceerde taken volgens Geavanceerde printerinstallatie. Test de printer en controleer of deze werkt met eventueel speciaal ingestelde opties voor LPD. De lokale host moet geautoriseerd zijn om de LPD-dienst op de verre host te gebruiken (zie Opdrachten van hosts op afstand beperken).

Als een printer een netwerkinterface heeft die compatibel is met LPD, dan is de printerhost in onderstaande beschrijving de printer zelf en de printernaam is de naam die voor de printer is ingesteld. Meer informatie staat in de documentatie bij de printer en/of de printernetwerkinterface.

Tip: Bij een HP LaserJet voert de printernaam text automatisch de CRLF-conversie uit. Het is dan niet nodig het script hpif te gebruiken.

Op hosts die toegang moeten krijgen tot de printer, moet in /etc/printcap een regel worden toegevoegd met het volgende:

  1. Geef de regel een willekeurige naam. Om het eenvoudig te houden kunnen wellicht het beste dezelfde namen en aliassen worden gebruikt als op de printerhost;

  2. Laat de optie lp expliciet leeg (:lp=:);

  3. Maak een wachtrijmap aan en geef de locatie op met de optie sd. LPD slaat hier afdrukopdrachten op alvorens ze naar de printerhost te sturen;

  4. Geef de naam van de printerhost op met de optie rm;

  5. Geef de naam van de printer op de printerhost op met de optie rp.

Dit is het. Conversiefilters, paginadimensies, enzovoort, hoeven niet in /etc/printcap opgegeven te worden.

Hier volgt een voorbeeld. De host rose heeft twee printers: bamboo en rattan. Gebruikers op de host orchid krijgen toegang tot deze printers. Hier volgt /etc/printcap voor orchid (uit Voorbladen afdrukken). Er stond in het bestand al een regel voor de printer teak. Voor de twee printers op de host rose zijn twee regels toegevoegd:

#
#  /etc/printcap voor host orchid - printers (op afstand) op rose toegevoegd
#

#
#  teak is lokaal; het is direct aangesloten op orchid:
#
teak|hp|laserjet|HP 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 is aangesloten op rose; stuur opdrachten voor rattan naar rose:
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
        :lp=:rm=rose:rp=rattan:sd=/var/spool/lpd/rattan:

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

Op orchid moeten wachtrijmappen worden aangemaakt:

# 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

Nu kunnen gebruikers op orchid afdrukken op rattan en bamboo. Een gebruiker op orchid geeft bijvoorbeeld de volgende invoer:

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

Dan kopieert LPD op orchid de opdracht naar de wachtrijmap /var/spool/lpd/bamboo en ziet dat het een DVI-opdracht is. Zodra de host rose ruimte heeft in zijn wachtrijmap bamboo, sturen de twee LPD's het bestand naar rose. Het bestand wacht in de wachtrij van rose totdat het succesvol is afgedrukt. Het wordt geconverteerd naar PostScript (aangezien bamboo een PostScript-printer is) op rose.

10.4.3.2. Printers met netwerkinterfaces

Netwerkkaarten voor printers zijn er in twee versies: een versie die een wachtrij nabootst (de duurdere versies), of versies die alleen de mogelijkheid geven om er informatie naar te sturen alsof het een seriële of parallelle poort is (de goedkopere versies). In Printers geïnstalleerd op andere hosts wordt het voor de duurdere beschreven.

Het formaat van /etc/printcap maakt het mogelijk om op te geven welke seriële, of parallelle poort gebruikt moet worden en (in geval van een seriële poort) de baud-snelheid, of er communicatie moet worden toegepast, vertragingen voor tabs, conversies voor nieuwe regelkarakters en meer. Er is geen mogelijkheid om een verbinding met een printer op te geven die op een TCP/IP of andere netwerkpoort luistert.

Om informatie naar een netwerkprinter te sturen, is het nodig een programma te ontwikkelen dat door tekst- en conversiefilters kan worden aangeroepen. Hier volgt een voorbeeld: het script netprint stuurt alle informatie van de standaard invoer naar een netwerkprinter. Als eerste argument wordt de hostnaam van de printer opgegeven en als tweede argument het poortnummer waarmee de verbinding moet worden opgezet. Er wordt alleen eenrichtingcommunicatie ondersteund (FreeBSD naar printer). Veel netwerkprinters ondersteunen tweewegcommunicatie. Het kan wenselijk zijn hiervan gebruik te maken (om printerstatus op te vragen, statistieken bij te houden, enzovoort).

#!/usr/bin/perl
#
#  netprint - Tekstfilter voor printer aangesloten op het netwerk
#  Geïnstalleerd in /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;

Dit script kan vervolgens in verschillende filters gebruikt worden. Stel dat een Diablo 750-N matrixprinter op het netwerk is aangesloten. Op poort 5100 accepteert de printer informatie om af te drukken. De hostnaam van de printer is scrivener. Hier volgt het tekstfilter voor de printer:

#!/bin/sh
#
#  diablo-if-net - Tekstfilter voor Diablo printer 'scrivener' luistert
#  op poort 5100. Geïnstalleerd in /usr/local/libexec/diablo-if-net
#
exec /usr/libexec/lpr/lpf "$@" | /usr/local/libexec/netprint scrivener 5100

10.4.4. Printergebruik beperken

Nu volgt informatie over het beperken van printergebruik. Het LPD-systeem maakt het mogelijk te bepalen wie er toegang heeft tot een printer, zowel lokaal als op afstand, of meerdere kopieën afgedrukt mogen worden, hoe lang opdrachten mogen zijn en hoe lang wachtrijen mogen worden.

10.4.4.1. Meerdere kopieën beperken

Het LPD systeem maakt het heel makkelijk voor gebruikers om meerdere afdrukken van een bestand te maken. Gebruikers kunnen opdrachten afdrukken met bijvoorbeeld lpr -#5 en krijgen dan vijf kopieën van elk bestand in de opdracht. De systeembeheerder kan beslissen of dit wenselijk is.

Wanneer meerdere kopieën onwenselijk zijn, kan de optie -# van lpr(1) worden uitgeschakeld door de optie sc in /etc/printcap op te nemen. Als gebruikers opdrachten versturen met de optie -#, zien ze het volgende:

lpr: multiple copies are not allowed

Als het mogelijk is van andere hosts af te drukken (zie Printers geïnstalleerd op andere hosts), moet de optie sc ook in /etc/printcap van de andere hosts aanwezig zijn. Anders kunnen gebruikers nog steeds multi-kopie opdrachten van andere hosts sturen.

Hier volgt een voorbeeld. Hieronder staat /etc/printcap voor de host rose. De printer rattan is redelijk krachtig, dus meerdere kopieën zijn toegestaan. De laserprinter bamboo is wat gevoeliger, dus meerdere kopieë zijn uitgeschakeld door de optie sc toe te voegen:

#
#  /etc/printcap voor host rose - beperk meerdere kopieën op 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:\
        :lp=/dev/ttyu5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:

Nu moet ook de optie sc worden toegevoegd in /etc/printcap van host orchid (tegelijk worden meerdere kopieën voor de printer teak uitgeschakeld):

#
#  /etc/printcap voor host orchid - geen meerdere kopieën voor lokale
#  printer teak of printer op afstand bamboo
teak|hp|laserjet|HP 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:

Door de optie sc te gebruiken, wordt het gebruik van lpr -#i voorkomen, maar dat weerhoudt gebruikers er nog steeds niet van om lpr(1) meerdere keren te aanroepen of meerdere keren hetzelfde bestand te versturen in een opdracht:

% lpr voorverkoop.teken voorverkoop.teken voorverkoop.teken voorverkoop.teken voorverkoop.teken

Er zijn vele manieren om dit misbruik te voorkomen (onder andere door het te negeren), welke vrij zijn om te verkennen.

10.4.4.2. Printertoegang beperken

Door gebruik te maken van het UNIX® groepmechanisme en de optie rg in /etc/printcap kan geregeld worden wie er op welke printer kan afdrukken. De gebruikers die toegang hebben tot een printer moeten in een groep worden geplaatst en deze groep moet in de optie rg worden genoemd.

Als gebruikers buiten de groep (inclusief root) naar de beheerde printer proberen te printen, worden ze begroet met het volgende bericht:

lpr: Not a member of the restricted group

Net als met de optie sc (suppress multiple copies: onderdruk meerdere kopieën) moet rg, indien wenselijk, ook op andere hosts worden opgegeven die ook toegang hebben tot printers (zie Printers geïnstalleerd op andere hosts).

In het volgende voorbeeld heeft iedereen toegang tot de printer rattan, maar alleen gebruikers in de groep artists kunnen gebruik maken van bamboo. Hier volgt het bekende /etc/printcap voor de host rose:

#
#  /etc/printcap voor host rose - beperkte toegang voor groep 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/ttyu5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:

De andere voorbeeldbestanden /etc/printcap (voor de host orchid) worden niet aangepast. Natuurlijk kan iedereen op orchid afdrukken op bamboo. Het kan zijn dat er sowieso alleen bepaalde gebruikers op orchid zijn toegestaan en dat deze gebruikers toegang mogen hebben tot de printer. Of wellicht niet.

Opmerking: Er kan per printer slechts één groep worden opgegeven.

10.4.4.3. Grootte van afdrukopdrachten bepalen

Als veel gebruikers toegang hebben tot printers kan het nodig zijn een limiet op te geven voor de grootte van de bestanden die gebruikers naar een printer kunnen sturen. Er is immers slechts beperkte ruimte op het bestandssysteem en er moet ook voldoende ruimte zijn voor opdrachten van andere gebruikers.

LPD heeft de mogelijkheid om met de optie mx een limiet op te geven voor het maximum aantal bytes van een bestand in een afdrukopdracht. De eenheden worden opgegeven in BUFSIZ blokken, die 1024 bytes groot zijn. Een nul voor deze optie betekent geen limiet aan de bestandsgrootte. Als de optie wordt weggelaten, wordt een standaardlimiet van 1000 blokken gebruikt.

Opmerking: De limiet heeft betrekking op de bestanden in een opdracht, niet op de totale grootte van een opdracht.

LPD weigert een bestand dat groter is dan de opgegeven limiet niet. In plaats daarvan plaatst het zo veel mogelijk van het bestand op de wachtrij, om dit vervolgens af te drukken. De rest wordt genegeerd. Of dit gedrag wenselijk is, is onderwerp van debat.

Nu worden limieten voor de voorbeeldprinters rattan en bamboo opgegeven. Aangezien de PostScript-bestanden van die artists nogal groot kunnen worden, krijgen ze een limiet van vijf megabyte opgelegd. Er wordt geen limiet opgelegd voor de platte tekst printer:

#
#  /etc/printcap voor host rose
#

#
#  Geen limiet op opdrachtgrootte:
#
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:

#
#  Limiet van vijf 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/ttyu5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:

Ook hier zijn de limieten alleen van toepassing op lokale gebruikers. Als toegang tot deze printers van andere hosts mogelijk is, worden deze gebruikers niet beperkt. Het is daarom nodig de optie mx ook in de /etc/printcap van de betreffende hosts op te geven. In Printers geïnstalleerd op andere hosts staat meer informatie over afdrukken op andere hosts.

Er is een andere gespecialiseerde manier om opdrachtgrootte voor printers op afstand te beperken (zie Opdrachten van hosts op afstand beperken.

10.4.4.4. Opdrachten van hosts op afstand beperken

Het wachtrijsysteem LPD beschikt over verschillende methoden om afdrukopdrachten van hosts op afstand te beperken:

Hostbeperkingen

Met de bestanden /etc/hosts.equiv en /etc/hosts.lpd kan worden ingesteld van welke hosts op afstand een lokale LPD-opdracht wordt geaccepteerd. LPD controleert of een inkomend verzoek afkomstig is van een host die wordt genoemd in een van deze bestanden. Zo niet, dan weigert LPD het verzoek.

Het formaat van deze bestanden is eenvoudig: één host per regel. /etc/hosts.equiv wordt ook gebruikt door het protocol ruserok(3) en heeft invloed op programma's als rsh(1) en rcp(1). Voorzichtigheid is dus geboden.

Als voorbeeld volgt hier /etc/hosts.lpd voor de host rose:

orchid
violet
madrigal.fishbaum.de

Dit betekent dat rose verzoeken accepteert van de hosts orchid, violet en madrigal.fishbaum.de. Voor iedere andere host die verbinding probeert te maken met LPD op rose, wordt de opdracht geweigerd.

Omvangbeperkingen

De hoeveelheid vrije ruimte die over moet blijven op een bestandssysteem waar een wachtrij zich bevindt kan ook worden ingesteld. Hiervoor moet een bestand met de naam minfree in de wachtrijmap worden aangemaakt. In dit bestand kan een getal worden gezet dat het aantal schijfblokken (512 bytes) aan vrije ruimte aangeeft dat beschikbaar moet blijven wil een opdracht worden geaccepteerd.

Hiermee kan worden gegarandeerd dat gebruikers op afstand een bestandssysteem niet vol kunnen schrijven. Ook kan hierdoor een soort voorrang worden gegeven aan lokale gebruikers: zij kunnen nog opdrachten plaatsen als de vrije schijfruimte al lang beneden de opgegeven limiet uit minfree is gekomen.

Als voorbeeld wordt een bestand minfree voor de printer bamboo toegevoegd. In /etc/printcap staat de juiste wachtrijmap:

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

De wachtrijmap wordt opgegeven met de optie sd. Er wordt een limiet van drie megabyte ingesteld (wat gelijk staat aan 6144 schijfblokken) voor de hoeveelheid vrije schijfruimte die op het bestandssysteem beschikbaar moet zijn voordat LPD een opdracht op afstand accepteert:

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

Met de optie rs in /etc/printcap kan worden geregeld welke gebruikers op afstand kunnen afdrukken op lokale printers. Als rs voorkomt voor een lokale printer accepteert LPD opdrachten van hosts op afstand als de gebruiker die de opdracht wil plaatsen ook een account heeft met dezelfde gebruikersnaam op de lokale host. Anders weigert LPD de opdracht.

Deze optie is met name nuttig in een omgeving waar (bijvoorbeeld) verschillende afdelingen een netwerk delen en gebruikers de grenzen van de afdeling overschrijden. Door ze een account te geven op een systeem kunnen ze de aangesloten printers gebruiken vanaf het systeem van hun eigen afdeling. Wanneer ze alleen gebruik mogen maken van de printers en niet van overige diensten op de computer, kunnen “tokenaccounts” worden aangemaakt, zonder thuismap en met een nutteloze shell als /usr/bin/false.

10.4.5. Printergebruik administreren

Het kan nodig zijn om afdrukken te doorbelasten. Inkt en papier kosten geld en er zijn onderhoudskosten. Printers zitten vol met bewegende delen en hebben de neiging kapot te gaan. Nu is er gekeken naar de printers, het gebruikerspatroon en de onderhoudskosten en op basis hiervan is een prijs vastgesteld per pagina (of per centimeter, per meter, of per wat dan ook). Hoe wordt nu een administratie bijgehouden van gemaakte afdrukken?

Het slechte nieuws is dat het wachtrijsysteem LPD hierbij niet echt helpt. Het administreren van afdrukken is erg afhankelijk van het type printer, het afdrukformaat en de wensen die een systeembeheerder heeft ten aanzien van het doorbelasten van printergebruik.

Om het administreren te implementeren, is het nodig om aanpassingen te maken in de tekstfilter (om platte tekst opdrachten te belasten) en de conversiefilters (om opdrachten in andere bestandsformaten te belasten), om pagina's te tellen, of de printer te vragen hoeveel pagina's er zijn afgedrukt. Het volstaat niet om het eenvoudige uitvoerfilter te gebruiken, aangezien dit niet in staat is het gebruik te administreren. Zie Filters.

In het algemeen zijn er twee manieren om gebruik te administreren:

Het wachtrijsysteem LPD ondersteunt beide methoden op eenvoudige wijze. Aangezien de filters (meestal) moeten worden aangeleverd, moet ook de code voor de administratie worden geleverd. Er is echter een voordeel: er is grote flexibiliteit in de administratiemethode. Zo kan bijvoorbeeld gekozen worden tussen periodieke of directe administratie. Er kan gekozen worden welke informatie opgeslagen wordt: gebruikersnamen, hostnamen, type opdracht, aantal afgedrukte pagina's, hoe lang het afdrukken duurde, enzovoort. Dit alles kan worden gedaan door de filters aan te passen.

10.4.5.1. Kort door de bocht printeradministratie

FreeBSD wordt met twee programma's geleverd waarmee periodieke administratie direct kan worden opgezet. Het zijn het tekstfilter lpf, beschreven in lpf: een tekstfilter en pac(8), een programma dat posten uit administratiebestanden verzamelt en optelt.

Zoals beschreven in de sectie over filters (Filters), roept LPD de tekst- en conversiefilters aan met de naam van het administratiebestand als argument. De filters kunnen dit argument gebruiken om te bepalen in welk bestand de gegevens voor de administratie moeten worden weggeschreven. De naam van dit bestand is afkomstig van de optie af uit /etc/printcap. Als er geen absoluut pad wordt opgegeven, dan is de locatie relatief aan de wachtrijmap.

LPD start lpf met paginabreedte en -lengte argumenten (afkomstig uit de opties pw en pl). Het filter lpf gebruikt deze argumenten om te bepalen hoeveel papier er gebruikt zal worden. Nadat het bestand naar de printer is gestuurd, schrijft het een post in het administratiebestand. De posten zien er als volgt uit:

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

Aangezien lpf geen ingebouwde logica voor bestandslocking kent, moet voor elke printer een apart administratiebestand gebruikt worden. Twee lpfs kunnen elkaars posten corrumperen als ze tegelijk in hetzelfde bestand schrijven. De optie af=acct in /etc/printcap biedt een makkelijke manier om er zeker van te zijn dat aparte bestanden worden gebruikt. Dan bevindt elk administratiebestand zich in de wachtrijmap van de betreffende printer en krijgt de naam acct krijgen

Wanneer het tijd is om met gebruikers af te rekenen voor hun afdrukken, kan het programma pac(8) gedraaid worden. Ga naar de wachtrijmap van de printer waarvoor betaald moet worden en typ pac. Er verschijnt een dollar-centrische samenvatting zoals het volgende:

  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

Dit zijn de argumenten die pac(8) verwacht:

-Pprinter

De printer waarvoor een samenvatting moet worden gegenereerd. Deze optie werkt alleen als er een absoluut pad is gegeven in de optie af in /etc/printcap.

-c

Sorteer de uitvoer op kosten, in plaats van alfabetisch op gebruikersnaam.

-m

Negeer de hostnamen in het administratiebestand. Met deze optie is de gebruiker smith op host alpha dezelfde gebruiker als smith op host gamma. Zonder deze optie zijn het verschillende gebruikers.

-pprijs

Bereken de prijs met prijs dollar per pagina of per voet, in plaats van de prijs uit de optie pc in /etc/printcap of twee cent (de standaard). De prijs kan worden opgegeven als een decimaal getal.

-r

Keer de sorteervolgorde om.

-s

Maak een bestand met een samenvatting van de administratie en leeg het administratiebestand.

namen

Druk de administratiegegevens alleen af voor gebruikersnamen namen.

In de standaard samenvatting die pac(8) genereert, is het aantal pagina's te zien dat iedere gebruiker vanaf een bepaalde host heeft afgedrukt. Wanneer de hostnaam niet van belang is (bijvoorbeeld omdat gebruikers iedere host kunnen gebruiken), gebruik dan pac -m om de volgende samenvatting te genereren:

  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

Om het verschuldigde bedrag te berekenen gebruikt pac(8) de optie pc uit /etc/printcap (standaard aantal van 200 of 2 cent per pagina). Specificeer, in honderden centen, de prijs per pagina of per voet die berekent moet worden. Deze waarde kan worden aangepast door pac(8) aan te roepen met de optie -p. De eenheden van de optie -p zijn echter in dollars, niet in honderden centen. Bijvoorbeeld,

# pac -p1.50

zorgt ervoor dat elke pagina 1,50 dollar kost. U kunt echt grote winsten maken met deze optie.

Tenslotte kan met pac -s de samenvatting worden opgeslagen in een bestand dat dezelfde naam krijgt als het administratiebestand van de printer, maar dan met _sum toegevoegd aan de naam. Vervolgens wordt het administratiebestand geleegd. Als pac(8) opnieuw wordt aangeroepen, herleest pac(8) het samenvattingsbestand om de startwaarden te bepalen en telt daar de informatie bij op van het standaard administratiebestand.

10.4.5.2. Hoe kan het aantal afgedrukte pagina's worden geteld?

Om ook maar de minste nauwkeurigheid bij het administreren te verkrijgen, is het nodig te weten hoeveel papier een afdrukopdracht gebruikt. Dit is het centrale probleem van het bijhouden van printerstatistieken.

Voor opdrachten met platte tekst is het probleem niet zo moeilijk op te lossen: het aantal regels in een opdracht wordt geteld en vergeleken met het aantal regels per pagina dat door een printer wordt ondersteund. Hierbij moet niet worden vergeten dat backspaces in het bestand regels overschrijven en dat lange logische regels worden afgedrukt als meerdere fysieke regels.

Het tekstfilter lpf (geïntroduceerd in lpf: een tekstfilter) houdt met deze zaken rekening bij het administreren. Als het nodig is een tekstfilter te schrijven dat ook het printergebruik moet bijhouden, dan is het nuttig de broncode van lpf te bestuderen.

Hoe worden andere bestandsformaten dan verwerkt?

Voor een DVI-naar-LaserJet, of DVI-naar-PostScript conversie kan het filter de diagnostische uitvoer van dvilj of dvips bekijken om te bepalen hoeveel pagina's er zijn geconverteerd. Voor andere formaten kan hetzelfde worden gedaan met behulp van de betreffende conversieprogramma's.

Deze methoden hebben echter als nadeel dat een printer eventueel niet alle pagina's ook daadwerkelijk afdrukt. Zo kan het papier vast komen te zitten, de toner opraken of de printer ontploffen, terwijl de gebruiker toch moet betalen.

Dus, wat kan hieraan worden gedaan?

Er is slechts één betrouwbare manier om nauwkeurig te administreren. Dat is met behulp van een printer die kan vertellen hoeveel papier er is gebruikt. Deze moet vervolgens worden aangesloten met een seriële lijn, of een netwerkverbinding. Bijna alle PostScript-printers hebben deze mogelijkheid, andere modellen en merken mogelijk ook (bijvoorbeeld Imagen netwerklaserprinters). De filters dienen voor deze printers aangepast te worden om het papierverbruik na elke opdracht te achterhalen en de administratieve informatie alleen op deze waarde te baseren. Er is geen noodzaak om foutgevoelig regels te tellen of bestanden te analyseren.

Natuurlijk kan een beheerder ook vrijgevig zijn en alle afdrukken gratis maken.