11 

11.1概要

FreeBSD支持许多种类的打印机,从最老式的impact打印机,到最新的激光打印机,都可以让你通过相关的应用程序来提供高质量的打印效果。

FreeBSD也可以通过网络来配置一个打印服务器。通过这种功能,FreeBSD可以从其他的计算机上得到打印任务,包括其他的FreeBSD计算机,WindowsMacOS主机。FreeBSD能够确保每个打印作业都能完成,并能够统计用户和机器的工作状况,以使它们能达到最佳的打印效果。FreeBSD也能生成“banner”页,来显示谁打了什么和打了多少。

阅读完这章,你将了解到:

             如何配置FreeBSD的后台打印(print后台打印系统)。

             如何安装打印机的过滤器,处理一些特殊的打印作业。包括转换打印文件的格式。

             如何在打印输出文件中启用headerbanner文件。

             如何通过连接到其他计算机来打印到打印机。

             如何直接连接到网络来打印到打印机。

             如何管理打印机的限制,包括打印尺寸的大小,以及阻止某些用户的打印。

             如何记录打印机的统计情况和用户使用打印机的情况。

             如何处理打印机出现的问题。

在阅读这章之前,你应当先了解:

             如何配置和安装一个新的内核(第9章)。

11.2介绍

要在FreeBSD下使用打印机,你需要设置伯克莱线性后台打印系统,也叫做LPD假脱机(spooling)系统。这是FreeBSD下控制打印机的标准。这一节将介绍LPD假脱机系统,以下将简称为LPD

如果你已经熟悉LPD或是其他的打印机spooling系统,你可以先跳到设置spooling系统那一节。LPD控制任何有关连接在本机上的打印机的事情,包括:

             控制本地打印机及网络上其他打印机的访问权限。

             接收用户传送的文件来打印。这些要打印的要求称为jobs

             利用队列来防止多个用户同时访问同一台打印机。

             在输出时打出header page(也称做bannerburst pages)。这样,用户可以在厚厚一打纸张中找出他们自己所打印的东西。

             为连接在串口上的打印机设置适当的通信参数。

             通过网络将工作送给另一台机器上的LPD 后台打印系统。

             执行特定的过滤器,让你的工作可以兼容于使用不同打印机语言的打印机。

             统计打印机的使用情况。

通过一个配置文件(/etc/printcap)或提供特定的过滤器,你可以启用LPD系统在不同的打印机上执行上面全部或部分的功能。

11.2.1为什么要使用后台打印系统

如果你的系统只有自己一个人在用,那么你可能会觉得既不需要权限控制,header page,或是统计打印机使用情况,为什么还要用后台打印系统?如果可以直接访问打印机,那么你仍然得使用后台打印系统,因为:

             LPD打印工作在后台执行,你不需要等待数据传送到打印机。

             LPD可以通过过滤器,在你的文件上加上日期/时间等信息,或是转换特别的文件格式(如TexDVI的文件)使打印机能处理。你不需要手动转换。

             很多免费及商业软件所提供的打印功能通常会需要用到你系统上的后台打印系统。你只要设置好spooling系统,将来可以很容易的让其他的程序使用打印机。

11.3基本设置

要使用带有LPD spooling系统的打印机,你需要同时设置好你的打印机硬件和LPD软件。设置分为两大部分:

             简单的打印机设置,这一节将告诉你如何连接打印机,告诉LPD如何与它通信,打印纯文本文件到打印机。

             高级打印机设置,这一节将告诉你如何让打印机打出各种不同格式的文件,header page,通过网络打印,设置访问权限以及统计打印机的使用情况。

11.3.1简单的打印机设置

这一节将介绍如何配置打印机硬件和LPD软件。包括:

           硬件设置 这一节说明如何将打印机接到计算机的连接端口。

           软件设置 这一节说明如何设置LPD 后台打印系统的配置文件(/etc/printcap)。

如果你要设置的是网络打印机,请参考使用网络数据传输接口的打印机这一节。

虽然这一节叫做简单的打印机设置,但其实是挺复杂的。让你的打印机可以配合LPD 后台打印系统是设置工作中最难的一部分。一旦你的打印机可以正常工作了,较高级的功能如打印header page和打印机使用情况统计反而比较容易设置。

硬件设置

这一节介绍有哪些方法可以将打印机连到我们的个人计算机上。有哪些通信端口,连接线以及内核的设置。如果你的打印机在你使用的计算机上可以通过其他操作系统来打印,你也许可以跳过这一节直接到软件设置那一节。

端口和线缆

几乎所有可以和PC连接的打印机都能支持下列两种或是其中一种接口:

             串行打印机通过串口和计算机传输数据。串行接口的配备及连接线可以容易的取得及安装。但是串行接口有时需要较特别的连接线及较复杂的设置。

             并行打印机通过并口和计算机传输数据。并口在市场上很普遍,连接线也很容易找得到,但是不容易自己制作。利用并口连接打印机十分的容易,通常不需要设置额外的通信选项。

并口有时也称做“Centronics”接口,这是根据打印机上面的接头来命名的。

通常,只有使用PostScript的打印机才需要用到双向传输。PostScript打印机可以说是十分复杂。事实上,PostScript的打印工作常常是由程序将工作送到打印机处理后,并不打出来,而是将结果再传回计算机。PostScript也使用双向传输将错误传回计算机。比如说PostScript程序有问题或是打印机卡纸。机器上的用户可能会需要这些信息。更进一步的,PostScript打印机统计打印情况最好的方式就是使用双向传输。比如说:你可先询问打印机启动以来一共打过几张,然后送出用户要打的东西,打完后再询问一共打了几张,由此就可得知得向用户收多少纸张的钱。

并行口

Centronics连接线通过并口连接打印机和计算机。打印机手册,计算机手册这两者都可以给你足够的安装说明。记住你所使用的是计算机的哪个并行口。在FreeBSD中,第一个并行口是/dev/lpt0。第二个则是/dev/lpt1,依此类推。

串行口

用适当的连接线通过串行口连接打印机和计算机。打印机手册,计算机手册这两者都可以给你足够的安装说明。如果你不确定你的连线是否为合适的串行口连接线,可以试试下面几种不同用途的线:

             连接调制解调器的线。这种线是一个接脚对一个接脚直接对接的。这种线也叫做“DTE-to-DCE”连接线。

             Null-modem连接线大部分是一个接脚对一个接脚直接对接,而有少部分接脚相互交换(如send datareceive data)。有少部分接脚则两端都是短路。这种线也叫做“DTE-to-DTE”连接线。

             并行打印机连接线,某些不常见的打印机需要这种线。这种线类似null-modem连接线,但是有些信号是送到相对应的接脚而不是两端短路。

你应当为打印机设置通信参数,通常可以利用打印机上的控制面板或DIP开关设置。选择你的计算机和打印机同时支持的最高传输速率(单位为bpsbit/s,也称做baud rate)。选择78的数据位。无,奇数或偶数的奇偶校验。12停止位。同时也选择流量控制的方式:无,XON/XOFF(也称作“in-band”“software”)流量控制。记住你的软件设置也要使用同样的值。

软件设置

这节说明如何设置FreeBSD下的LPD spooling系统,使其能打印。

下列是所需的步骤:

1.         如果需要的话,设置你的,使该连接端口可被打印机使用。内核设置这一节将告诉你需要做些什么。

2.         如果你使用的是并行口,那么你得设置并口的通信模式。设置并列端口的通信模式这一节有详细的说明。

3.         测试操作系统是否可以将数据送给打印机。检查打印机连接状况这节将给你一些关于这一方面的建议。

4.         修改/etc/printcap以正确设置LPD/etc/printcap设置文件一节将告诉你如何做。

内核配置

操作系统的内核为了能配合某些设备需要重新编译。而串口和并口就是这些设备之一。如果你的内核目前并不支持你想用的串口或并口,那么可能需要将它们加入内核设置并重新编译。如果要检查你的内核目前是否支持串口,可以用这个命令:

# dmesg | grep sioN

其中N是串口的编号,从0开始计算。如果你得到的结果类似下面这个样子:

sio2 at 0x3e8-0x3ef irq 5 on isa

sio2: type 16550A

表示内核支持这个通信端口。

如果要检查你的内核目前是否支持并行口,可以用这个命令:

# dmesg | grep lptN

其中N是并行口的编号,从0开始计算。如果你得到的结果类似

lpt0 at 0x378-0x37f on isa

表示内核支持这个通信端口。

你可能会需要重新设置内核使得操作系统可以辨认并使用你连接打印机的并口或串口。

如果要让你的内核支持串口,请参考关于重新编译内核的那一节。如果要让你的内核支持并口,请参考关于重新编译内核的那一节以及下一节。

为端口添加/dev记录

既然内核已经支持你所需的并口或串口,你仍然需要一个程序接口在系统里协助传送和接收数据。这也是/dev设备文件存在的目的。

为你的端口添加一个/dev记录:

1.    su命令切换成root

2.    更改当前的目录到/dev下:

# cd /dev

3.    输入:

# ./MAKEDEV port

其中port是你想要建立的设备文件名称。如果是第一个并口,可以用lpt0。如果是第二个并口,可以用lpt1,依此类推。如果是第一个串口,可以用ttyd0。如果是第二个串口,而用ttyd1。依此类推。

4.    输入:

# ls -l port

以确定你刚刚是否建立成功。

为并口设置通信模式

当你决定要用并口时,在FreeBSD下你可以决定要用中断驱动(interrupt-driven)或是轮询(polled)方式与打印机沟通。

             中断驱动是GENERIC 内核里默认的方式。如果选择这个方式,操作系统将利用IRQ来判断打印机是否已经准备好接收数据。

             而轮询的方式则是由操作系统一直重复地去询问打印机是否已经准备好可以接收数据。如果打印机已经准备好了,那么内核再将要打印的数据送过去。

中断驱动的方式较快但是要占用一个IRQ。你可以从上面两者任选一个可以正常工作的来使用。设置通信模式有两种方式:设置内核或是使用lptcontrol程序。

通过配置内核来设置通信模式:

1.    编辑你的内核设置文件。找出或是自行加入lpt0这一项。如果你要设置使用第二个并口,那就加入lpt1这项。如果是第三个并口就用lpt2,依此类推。

             如果你要设置使用中断驱动模式,那么要指定irq

device lpt0 at isa? port? tty irq N vector lptintr

其中N是并口所使用的IRQ编号。

             如果你要用轮询模式,那么就不要指定irq

device lpt0 at isa? port? tty vector lptintr

2.    将设置文件存储好后,重新编译,安装内核并重新启动。你可以参考内核配置(第9章)那一章更详细的说明。

如果你想用lptcontrol来设置通信模式:

1.    输入:

# lptcontrol -i -u N

lptN设置为中断驱动模式。

2.    输入:

# lptcontrol -p -u N

lptN设置为轮询模式。

你可以把上面的命令加到你的/etc/rc.local文件里使得每次启动时都可以自动设置。你可以查看lptcontrol的联机手册了解更多有关的信息。

检查打印机的通信状况

在设置spooling系统前,你应该先确定操作系统可以成功地将数据送到你的打印机。将打印机的连接和spooling系统分开来测试会较容易。

你可以送一些文字来测试打印机。打印机应该会马上将它们收到的数据打出来。lptest这个程序会送96行每行96ASCII文字的数据给打印机以协助测试。

使用PostScript(或是其他语言)的打印机测试起来较复杂。我们得先写一个较小的测试程序,像下面这样:

%!PS

100 100 moveto 300 300 lineto stroke

310 310 moveto /Helvetica findfont 12 scalefont setfont

Is this thing working? show

showpage

注意:上面这个小程序是给使用PostScript的打印机用的,不能给比如说Hewlett Packard公司的PCL语言使用。PCL语言可以让你打印纯文本,同时里面夹杂PCL特别的命令。PostScript不能直接打印纯文本,因此对于这样的打印机,我们必须做一些特别的设置。

检查一下并口打印机

这节将告诉你如何检查FreeBSD是否可以使用接在并口的打印机。

测试并口上的打印机:

1.    su命令切换成root

2.    将数据传送给打印机。

             如果这个打印机可以直接打印纯文本,请使用lptest。输入:

# lptest > /dev/lptN

其中N是打印机所连接的并列端口。从0开始计算。

             如果这个打印机使用PostScript或其他的打印机语言,那么送一个小小的测试程序给打印机。输入:

# cat > /dev/lptN

然后,一行接着一行,小心的把你的命令打进去,因为按下ENTER后,就无法再修改了。当你输入完毕后,按CONTROL+D或是其他产生文件结尾字符的按键。或者是你可以将测试程序放在一个文件里并输入:

# cat file > /dev/lptN

其中file就是存储你测试程序的文件名。

你应该可以看到有一些东西打出来了。如果打出来的数据看起来不大正确,别担心,我们等一会就修正它们。

检查一个串口打印机

这节将告诉你如何检查FreeBSD是否可以使用接在串口的打印机。

测试串口上的打印机:

1.    su命令切换成root

2.    编辑/etc/remote这个文件,并加入下列几行:

printer:dv=/dev/port:br#bps-rate:pa=parity

其中port指的是串行端口的设备记录(ttyd0ttyd1等等),bps-rate指的是该串口的传输速度,而parity是设置打印机是否需要奇偶校验(这个值可以是evenoddnonezero)。

下面这个例子是一台连接在串行端口上以19200 bps传输的,同时不使用奇偶校验的打印机设置方式:

printer:dv=/dev/ttyd2:br#19200:pa=none

3.    tip命令连上打印机。输入:

# tip printer

如果这步失败的话,再次编辑/etc/remote文件同时用/dev/cuaaN代替/dev/ttydN

4.    将数据传送给打印机。

如果这个打印机可以直接打印纯文本,请使用lptest。输入:

% $lptest

如果这个打印机使用PostScript或其他的打印机语言,那么送一个小小的测试程序给打印机。一行接着一行,非常小心地将程序输入,因为退格键或是其他编辑时常用的按键,对打印机可能有特殊的意义。最后你可能要打一个给打印机的文件结尾的字符,让它知道程序结束了。对PostScript打印机来说,是用CONTROL+D键。

或者是你可以将测试程序放在一个文件里并输入:

%>file

其中file就是存储测试程序的文件名。用tip将这个文件送给打印机后,按下文件结束键。

你应该可以看到有一些东西打出来了。如果打出来的数据看起来不大正确,别担心,我们以后会修正它们。

启用后台打印系统:编辑/etc/printcap文件

到目前为止,你的打印机应该已经连接好了,内核应该也设置无误了,而且也可以传送数据给打印机了。现在,我们应该可以开始设置LPD来控制打印机了。

LPD的设置文件是/etc/printcap。每当后台打印系统被使用时,LPD spooling系统就会读这个文件,所以只要这个文件一被修改,马上就会生效。

printcap文件的格式是很简单的。用你喜欢的编辑器对/etc/printcap这个文件做一下修改。这个文件的格式写法和其他的设置文件如/usr/share/misc/termcap/etc/remote是相同的。关于这些设置文件的格式,请参考cgetent的联机手册。

要建立一个简单的后台打印系统,需要完成下列步骤:

1.         为你的打印机选择一个名字(和几个好记的别名),并把它们放在/etc/printcap文件中。请阅读为打印机取名这一节。

2.         通过插入sh功能关闭打印header page的功能(默认是打开此功能)。请阅读不打印Header page这一节。

3.         sd功能指定一个目录给后台打印系统用。请阅读建立Spooling目录这一节。

4.         /etc/printcap设置文件里用lp命令指定打印机连接端口在/dev下使用的设备文件。请阅读辨认打印机设备这一节。如果你的打印机是接在串口,那么可以用fsfcxs以及xc等来设置通信参数。请阅读设置后台打印系统的通信参数。

5.         安装一个简单的文本输入过滤器。请参考安装文本过滤器这一节。

6.         利用lpr命令打印以测试设置是否正确。请阅读测试及疑难解答这两节。

注意: 使用特定语言的打印机,比如说PostScrit打印机,无法直接打印纯文本。上面以及下面要介绍的方法将假设你所要打印的文件都是不需要转换就能让打印机直接了解的。

用户通常会期望它们可以直接将纯文本的数据直接由打印机输出,而使用LPD打印的程序通常也是这么假设的。如果你的打印机使用某个特定的打印机语言,且希望可以同时处理特定打印机语言的数据以及纯文本的数据,那么应该要另外再多安装一项以前没有提到的东西:纯文本转成PostScript(或其他打印机语言)的自动转换程序。在PostScript打印机上打印纯文本这一节将告诉你怎么做。

为打印机命名

第一就是为你的打印机取一个名字。此外,也可为你的打印机取很多别名,因此,你要取符合功能的或是古怪的名字都可以。

/etc/printcap里定义的打印机,至少要有一台取lp别名。这是默认的打印机名称。如果用户没有环境变量PRINTER设置打印机的名称,且在LPD的命令也没有指定任何打印机的话,那么别名为lp的打印机就会被视为默认的打印机。

通常,我们会将一台打印机的最后一别名取为它的全名,包括制造商以及型号。

当你将打印机的名称及别名设置在/etc/printcap文件里时,打印机的名称一定要放在最左边的字段。其他的别名则以垂直的线(|)分开,而在最后一个别名以后加一个冒号(:)。

在下面的例子里,我们大略描述一下/etc/printcap的骨干。这个例子里定义了两台打印机。(Diablo 630以及Panasonic KX-P4455 PostScript激光打印机。):

    #

#  /etc/printcap for host rose

    #

rattan|line|diablo|lp|Diablo 630 Line Printer:

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:

在这个例子里,第一台打印机取名为rattan而它的别名有linediablolp以及Diablo 630 Line Printer。这台打印机有lp这个别名,因此它也是默认的打印机。第二台取名为bamboo,而它的别名有psPSSpanasonic以及Panasonic KX-P4455 PostScript v51.4

不打印头文件

LPD spooling系统默认是为每个打印工作打印header page的。Header page包括了送出打印工作的用户名称,送出工作的机器名称以及工作的名称。不幸的是,这些额外的信息可能会妨碍我们做简单的打印机设置测试,因此我们想不要打印header pager

/etc/printcapsh命令为特定的打印机设置不打印header page。这里有一个在 /etc/printcap里使用sh的例子:

    #

#  /etc/printcap for host rose - no header page anywhere

    #

rattan|line|diablo|lp|Diablo 630 Line Printer:\

:sh:

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\

:sh:

注意:我们使用的正确格式:打印机定义的第一行得从第一个字开始写的,而其后的每一行用TAB键往内缩一格。而一行如果写不完需要接到下一行时,则以反斜线字符结尾。

建立spooling目录

下一步就是建立一个spooling目录,一个在打印时会用到以及存放一些后台打印系统需要文件的地方。

通常我们会将spooling目录指定在/var/spool目录下。你不需要备份spooling目录,而建立它也只要以mkdir命令即可。

通常我们会将spooling目录以打印机的名称建立,如下所示:

# mkdir /var/spool/printer-name

然而,如果在你的网络中有很多打印机的话,也许会希望将所有的spooling目录放在一个LPD专用的目录下。以我们的打印机rattanbamboo为例:

# mkdir /var/spool/LPD

# mkdir /var/spool/LPD/rattan

# mkdir /var/spool/LPD/bamboo

注意: 如果你关心的是用户打印数据的隐私,那么应该要将spooling目录的权限做适当的设置。Spooling目录应该要属于daemon这个用户同时并允许它读,写及搜索,而其他人都无法访问此目录。因此,我们应该要这样设置:

# chown daemon.daemon /var/spool/LPD/rattan

# chown daemon.daemon /var/spool/LPD/bamboo

# chmod 770 /var/spool/LPD/rattan

# chmod 770 /var/spool/LPD/bamboo

最后,在/etc/printcap文件里,你可以用sd命令来指定spooling目录:

#

#  /etc/printcap for host rose - added spooling directories

#

rattan|line|diablo|lp|Diablo 630 Line Printer:\

:sh:sd=/var/spool/LPD/rattan:

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\

:sh:sd=/var/spool/LPD/bamboo:

注意:打印机的名字一定是在定义第一行的第一个字,而其他行都要以TAB缩进。如果需要换行则需要在行末加上反斜线字符。

如果你没有用sd指定spooling目录,那么spooling系统默认的使用目录/var/spool/LPD

识别打印机设备

在为通信端口添加/dev记录那节里,我们指出了FreeBSD将使用/dev目录下的哪个记录来与打印机通信。现在我们要告诉LPD这个信息。当spooling系统有工作要打印时,它将会告诉过滤器(负责送数据给打印机)使用指定的设备。

/etc/printcap文件中用lp列出/dev记录路径。

在我们的例子中,我们假设rattan使用第一个并口,而bamboo使用第六个串口。因此在/etc/printcap中我们设置:

    #

#  /etc/printcap for host rose - identified what devices to use

    #

rattan|line|diablo|lp|Diablo 630 Line Printer:\

:sh:sd=/var/spool/LPD/rattan:\

:lp=/dev/lpt0:

   

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\

:sh:sd=/var/spool/LPD/bamboo:\

:lp=/dev/ttyd5:

如果你在/etc/printcap文件中没有为打印机指定lpLPD将默认使用/dev/lp/dev/lp当前并不存在于FreeBSD中。

如果你现在安装的打印机是连接在并口上,那么请跳至安装文本过滤器这一节,否则,请按照下面这一节继续设置。

配置后台打印系统通信参数

对于连接在串口上的打印机,LPD可以设置传输速率,奇偶校验,以及其他的通信参数,这对发送数据到打印机上的过滤器非常有好处。因为:

           你只要编辑/etc/printcap文件就可以使用不同的通信参数。不需要去重新编译你的过滤器。

           允许spooling系统在多台打印机,多种不同通信参数设置的情况下用同一个过滤器。

/etc/printcap设置文件里,下列命令控制lp所指定的通信端口:

br#bps-rate

设置通信端口传输速度为bps-rate,其中bps-rate可以是50751101341502003006001200180024004800960019200或是38400 bit-per-second

fc#clear-bits

打开设备后,清除sgttyb结构里的标记位clear-bits

fs#set-bits

设置sgttyb结构里的标记位set-bits

xc#clear-bits

打开通信端口后,清除本地模式位clear-bits

xs#set-bits

设置本地模式位set-bits

关于fcfsxc以及xs有关各个bit的说明,请参考/usr/include/sys/ioctl_compat.h

LPD打开由lp所指定的通信端口时,会先读取sgttyb这个结构,然后清掉fc命令所指定的位再设置由fs命令所指定的位。设置完成后,才开始使用这个结构。同样的,对local模式位设置也是以一样的方式处理。

让我们在我们的例子里为第六个串行端口设置这些位。我们会将传输速率设置成38400 bps。而在标记位方面,我们会设置TANDEMANYPLITOUTFLUSHO以及PASS8这些位。而local模式位,我们将设置LITOUT以及PASS8位:

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\

:sh:sd=/var/spool/LPD/bamboo:\

:lp=/dev/ttyd5:fs#0x82000c1:xs#0x820:

安装文本过滤器

现在可以开始设置LPD用什么文本过滤器送工作给打印机。一个文本过滤器也叫做输入过滤器。当LPD有东西要打印时,它就会执行这个程序。当LPD运行这个程序时,它会将过滤器的标准输入设为要打印工作的标准输入,而过滤器的标准输出则送给以lp命令指定的通信端口。因此过滤器必须能从标准输入读入要打印的东西,做适当的处理后,将结果从标准输出送出。而这些输出就会被打出来。请参考过滤器的运作方式这一节以更进一步的了解过滤器。

在我们的打印机设置里,文本过滤器可能只是一个执行/bin/cat命令的shell脚本将工作送给打印机。FreeBSD里有一个叫做lpf的过滤器能处理倒退,底线等打印机可能无法正确处理的数据。当然,你也可以用任何你想用的过滤器。关于lpf这个过滤器在文本过滤器:lpf这一节里有更详细的说明。

首先,让我们做一个简单的shell脚本文本过滤器,/usr/local/libexec/if-simple。用你熟悉的编辑器编辑这个文件:

#!/bin/sh

    #

# if-simple - Simple text input filter for LPD

# Installed in /usr/local/libexec/if-simple

#

# Simply copies stdin to stdout.  Ignores all filter arguments.

/bin/cat && exit 0

exit 2

然后要让这个文件可执行:

# chmod 555 /usr/local/libexec/if-simple

同时,在/etc/printcap设置文件里用if命令告诉LPD来使用这个过滤器。在下面的例子里,我们在/etc/printcap中为两台打印机都指定了过滤器:

#

#  /etc/printcap for host rose - added text filter

#

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:fs#0x82000e1:xs#0x820:\

:if=/usr/local/libexec/if-simple:

打开LPD

LPD/etc/rc运行,通过使用LPD_enable来控制。默认是NO。如果你还没有启用它,可以加入下面这行到/etc/rc.conf,然后重新启动计算机或只运行LPD

    LPD_enable=“YES”

    # LPD

测试

你已经把LDP需要的设置都完成了。不过,我们需要测试看看这些设置是否可以正确地工作。测试的方法就是打出一些东西。如果要用LPD系统来打印,我们可以使用lpr这个命令来送出一些打印工作。

你可以使用检查打印机连接状况这一节里介绍的lprlptest来产生一些测试文字。

测试简单的LPD设置:

输入:

# lptest 20 5 | lpr -Pprinter-name

其中printer-name/etc/printcap里的某一台打印机名称或别名。如果要测试默认的打印机,那么在执行lpr命令时不要指定-P这个参数。再一次的提醒,如果你要测试的是PostScript打印机,那么请传送PostScript程序给打印机,而不要用lptest。你可以将程序放在一个文件里然后输入lpr file

如果是PostScript打印机,你应该会得到程序输出的结果。如果你是用lptest的话,那么你的结果看起来应该是下面这个样子:

!”#$%&'()*+-./01234

“#$%&'()*+-./012345

#$%&'()*+-./0123456

$%&'()*+-./01234567

%&'()*+-./012345678

如果要做更进一步的测试,你可以下载更大的程序(给某个特定打印机语言的打印机使用)或是在执行lptest时加一些额外的参数。例如lptest 80 60将会产生60行每行80个字符的测试数据。

如果打印机并没有反应,请参考疑难解答这一节。

11.4高级打印机设置

这一节我们要讨论的是处理特定文件格式的过滤器,header page,用网络打印机打印以及打印机访问权限及打印情况统计的设置方式。

11.4.1过滤器

虽然LPD负责处理网络通信设定,队列,访问权限控制,以及其他许多打印相关的工作,但最重要的工作还是由过滤器来做。过滤器是负责与打印机沟通,处理设备依存关系,以及一些其他特殊的需求。我们在之前设置打印机时安装了一个最简单,但是可以配合大部分打印机工作的文本过滤器(请阅读安装文本过滤器这一节)。

然而,如果我们想要更方便地转换格式,统计打印机使用情况,打印特别的打印机字体等等,我们应该先了解过滤器是如何运作的。这些事情都是由过滤器处理的。不幸的是,通常你得自己提供特定的过滤器。不过值得庆幸的是,有很多一般用途的过滤器可以用,如果没有的话,要自己做应该也很容易。

FreeBSD提供了一个过滤器/usr/libexec/lpr/lpf。这个过滤器可以让大部分的打印机打印纯文本(它只处理文件中的倒退字符以及TAB字符,并不做统计等工作)。在FreeBSDport里也搜集了许多种不同的过滤器。

在这一节里,我们将要讨论下面这些东西:

             过滤器如何工作这一节将告诉你过滤器在打印过程中所扮演的角色。你可以了解LPD使用过滤器时做了哪些动作。这些知识也能让你将来遇到过滤器相关的问题时能找出问题的症结。

             LPD将所有的打印机都视为可以直接打印纯文本。因此使用PostScript(以及使用其他语言)的打印机就无法直接打出纯文本。在PostScript打印机上打印纯文本这一节将告诉你该怎么做才能解决这个问题。如果你有一个PostScript打印机,那么我建议你看看这一节。

             PostScript是一种受欢迎的输出格式。有些人(包括我)直接撰写PostScript的程序代码。但是PostScript打印机很贵。 用非PostScript打印机仿真PostScript打印机这一节告诉你如何进一步修改打印机的文本过滤器使得非PostScript打印机也能打印PostScript的数据。如果你没有PostScript打印机,我建议你看看这一节。

             转换用的过滤器这一节说明如何让特殊的文件格式转换自动化,比如将图形或排版的数据转换成你的打印机所能理解的。读完这一节后,你应该可以用lpr -t命令打印troff数据,或是用lpr -d命令打印TeX DVI数据,或是用lpr -v命令打印光栅影像数据,等等。我建议阅读这一节。

             输出用的过滤器这一节说明一个LPD不常用的功能:输出用的过滤器。除非你要打印header page(请阅读Header Page这节),不然你可以略过这一节。

             文本过滤器:lpf这一节介绍lpf命令。这是由FreeBSD提供给一般的行式打印机(或类似行式打印机的激光打印机)使用的简单文本过滤器。如果你希望用一个快速的方法来统计打印纯文本的情况,或是你想要消除打印机对倒退字符的错误打印,那么你应该考虑使用lpf命令。

过滤器如何工作

上面曾经提到,过滤器是一个由LPD运行处理打印机与通信端口间沟通的程序。当LPD要打印文件时,它会设置过滤器的标准输入到文件去打印,它的标准输出给打印机打印,和它的标准错误记录到日志文件(在/etc/printcap/dev/console中默认的用lf来指定)。

LPD要使用哪个过滤器或是要给过滤器哪些参数是由/etc/printcap文件以及用户给lpr命令的参数决定的。举例来说,如果用户输入lpr -t,那么LPD将会使用tf作为目标打印机所指定的troff过滤器。如果用户想打印的是纯文本,那么LPD将会使用由if所指定的(大部分的时候是这样子的,详情请阅读输出用的过滤器这一节)。

/etc/printcap文件里你可以设置三种不同种类的过滤器:

             文本过滤器,在LPD的文件中常称为输入用过滤器。通常将它作为默认的过滤器,负责处理一般的文字打印。LPD将所有打印机都视为可以直接打印纯文本,所以这个过滤器的任务就是将打印机无法处理的字符及格式,转换为打印机所能处理的。如果你需要做打印情况的统计,那么过滤器需要计算总行数及每页行数来统计页数。使用文本过滤器的方式为:

filter-name [-c] -wwidth -llength -iindent -n login -h host acct-file

其中

-c

如果工作以lpr -l命令送出,那么就会有这个参数

width

值是由/etc/printcap文件中的pw(每页的字符宽度)所指定的。默认为132

length

是由pl(每页的行数)所指定,默认为66

indent

是由lpr -i命令所指定的缩进字数,默认是0

login

是打印该文件的用户帐户名称。

host

是送出工作的机器名称。

acct-file

是由af所指定的统计数据文件名称。

             转换用的过滤器负责将指定文件格式转换成打印机可以打出的格式。举例来说,ditroff排版数据无法直接交由打印机打印,不过你可以安装负责转换ditroff文件的过滤器将ditroff数据转换成打印机可以打印及处理的格式。转换用的过滤器这一节将会有更详细的说明。如果你需要做打印情况的统计,那么转换用的过滤器也需要做统计的工作。使用转换用的过滤器的方式为:

filter-name -xpixel-width -ypixel-height -n login -h host acct-file

其中pixel-width是由px所指定的值(默认为0),而pixel-height是由py所指定的值(默认为0)。

             输出用过滤器是当你没有文本过滤器,或是要打印header page时才使用。根据我的经验,输出用过滤器是很少用到的。输出用的过滤器这一节将介绍这些过滤器。输出用过滤器只接收两个参数,如下所示:

filter-name –w width –l length

参数-w-l的意思和文本过滤器中的意思是一样的。

而过滤器也应该要以下列的状态情况来结束程序:

exit 0

如果过滤器成功地把文件打出。

exit 1

如果过滤器打印失败了而想要让LPD再呼叫一次过滤器重新打印,那么就以这个值结束。LPD收到这个值以后,就会再重试打印。

exit 2

如果过滤器打印失败且不想再尝试了,那么就以这个值结束。LPD收到这个值将不会再重试同时放弃打印这个文件。

FreeBSD里提供的过滤器:/usr/libexec/lpr/lpf利用每页字符宽度及每页行数来判断什么时候要换页以及如何统计打印机打印情况。而以用户帐户,机器以及统计数据文件来记录打印的情况。

如果你想要购买过滤器,得先了解它们是否兼容于LPD。如果要兼容的话,它们必须能处理上面所列的参数。如果你想要自己写过滤器来用,那么它们一样要处理上面所列的参数以及程序结束码。

postscript打印机上打印纯文本

如果你的计算机只有你一个人在用而且你使用的是PostScript(或是其他的打印机语言)打印机,你也确定你决不会将纯文本的数据交给你的打印机打印,且不会使用其他会将纯文本送给你的打印机的程序,那么你就不需要阅读这一节。

但是,如果你需要能处理PostScript及纯文本的数据,那么你就得对你的打印机再做一番设置。我们首先要有一个文本过滤器可以查出送过来的数据是纯文本还是PostScript。所有的PostScript文件都是%! (对于其他的打印机语言,请参考你的打印机手册)。如果一份工作的最前面两个字符是这样的话,我们收到的就是PostScript工作,而我们可以直接把这份工作交给打印机处理。如果不是的话,那么过滤器就得把这些文字转换成PostScript,然后再打印这些结果。

那我们要怎么设置呢?

如果你是用串行端口上的打印机,有一个好方法就是安装lprpslprps是给PostScript打印机用的过滤器,它负责做打印机的双向沟通。它会将打印机的状态详细地更新到记录文件里,这样用户及管理者都可以清楚地看到打印机的状态。(如“toner low”或是卡纸)。更重要的是,它还包括了一个叫做psif的程序,如果查出输入的工作是纯文本,则呼叫textps这个程序(这是由lprps所提供的)将纯文本转换成PostScript。最后,它会呼叫lprps将工作送给打印机打印。

LprpsFreeBSD Ports Collection的一部分。当然,你可以自己取得,编译及安装。安装完lprps以后,只要指定psiflprps的程序之一)的路径即可。如果你从port里安装了lprps,那么在/etc/printcap文件里为串口的PostScript打印机添加下面这条记录:

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

你应该要使用rw命令以告诉LPD将打印机打开为读写模式。

如果你是使用接在并口的PostScript打印机(因此无法使用lprps和打印机双向沟通),那么你可以使用下面的shell脚本作为文本过滤器:

#!/bin/sh

#

#  psif - Print PostScript or plain text on a PostScript printer

#  Script version; NOT the version that comes with lprps

#  Installed in /usr/local/libexec/psif

#

   

read first_line

first_two_chars='expr “$first_line” : '\..\''

   

if [ “$first_two_chars” = “%!” ]; then

#

#  PostScript job print it.

#

echo “$first_line” && cat && printf “\004” && exit 0

exit 2

else

#

#  Plain text convert it then print it.

#

echo “$first_line”; cat | /usr/local/bin/textps && printf “\004” && exit 0

exit 2

fi

在上面的脚本里,textps是我们个别安装来将纯文本转成PostScript的程序。你可以使用任何将文本转换成PostScript的程序。FreeBSD Ports Collection里(第4章)有一个叫做a2ps的程序能做文本转成PostScript的工作,你也许可以试试。

在没有postscript的打印机上模拟postscript

PostScript是高品质打印的de facto标准。然而,PostScript也是一个昂贵的标准。值得庆幸的是,在FreeBSD下有个叫做Ghostscript的程序能仿真PostScript工作,这是由Alladin Enterprises所开发的免费程序。Ghostscript可以读取大部分PostScript文件并且将其结果输出到许多不同的设备上,包括许多非PostScript的打印机。只要安装Ghostscript并为打印机设置一个特殊的文本过滤器,你可以让你的非PostScript打印机接收PostScript的命令。

如果你从FreeBSD Ports Collection安装Ghostscript,那么你一样也可以很快地取得,编译并安装它。

要仿真PostScript,我们要有一个过滤器来判断我们要打印的是不是PostScript文件。如果不是,那么这个文件就直接交由打印机处理。否则,我们得先用Ghostscript将文件转换成打印机可以处理的。

这里有一个例子:下面的脚本是给Hewlett Packard DeskJet 500打印机用的文本过滤器。如果是其他的打印机,将gsGhostscript)命令的-sDEVICE参数换成你使用的设备即可。(你可以用gs -h这个命令得到目前系统安装的Ghostscript支持哪些设备)。

#!/bin/sh

    #

#  ifhp - Print Ghostscript-simulated PostScript on a DeskJet 500

#  Installed in /usr/local/libexec/hpif

 

#

#  Treat LF as CR+LF:

#

printf “\033&k2G” || exit 2

 

#

#  Read first two characters of the file

#

read first_line

first_two_chars='expr “$first_line” : '\..\''

   

if [ “$first_two_chars” = “%!” ]; then

#

#  It is PostScript; use Ghostscript to scan-convert and print it.

#

#  note that PostScript files are actually interpreted programs

#  and those programs are allowed to write to stdout which will

#  mess up the printed output.  So we redirect stdout to stderr

#  and then make descriptor 3 go to stdout and have Ghostscript

#  write its output there.  Exercise for the clever reader:

#  capture the stderr output from Ghostscript and mail it back to

#  the user originating the print job.

#

exec 3>&1 1>&2

/usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \

o     sOutputFile=/dev/fd/3 - && exit 0

   

#

/usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 -sOutputFile=- - \

&& exit 0

else

#

#  Plain text or HP/PCL so just print it directly; print a form

#  at the end to eject the last page.

#

echo $first_line && cat && printf “\033&l0H” && exit 0

fi

exit 2

最后,你需要用if来指定这个过滤器:

:if=/usr/local/libexec/hpif:

这么一来,你可以输入lpr plain.textlpr whatever.ps,这两者应该都可以正确打印。

转换用的过滤器

在完成上面简单的打印机设置这一节所介绍的设置后,下面要做的就是为我们还想要使用的文件格式(除了ASCII纯文本外)安装转换用的过滤器。

为什么要安装转换用的过滤器?

转换用的过滤器让打印不同格式的文件变得很简单。举例来说,如果我们常常用TeX来产生文件,但是我们的打印机是PostScript的。因此我们不能直接将由TeX产生的DVI文件由打印机打出,而要先转换成PostScript的格式才能输出。这些转换的命令如下:

% dvips seaweed-analysis.dvi

% lpr seaweed-analysis.ps

如果我们安装了DVI文件的转换程序,那么我们每次要打印时就可以省去自己转换格式的工作,而交由LPD自己转换。因此,我们要打印DVI文件时只要这一步就可以了:

% lpr -d seaweed-analysis.dvi

只要在使用LPD时加上-d参数,LPD就会将DVI文件转换后再正确地打出。输出格式及转换的参数这一节里有详细的列出转换用的参数。

对于每一个转换用的参数,我们必须为打印机安装合适的转换用过滤器,同时在 /etc/printcap文件里指定该过滤器。转换用的过滤器和文本过滤器很相似(请阅读安装文本过滤器这一节),除了它不是打印纯文本,过滤器将把文件转换成打印机可以处理的格式。

我应该如何使用转换用的过滤器?

你应该安装你想使用的转换用过滤器。如果你要打印DVI数据,那么应该安装DVI过滤器。如果你要打印troff数据,那么应该安装troff过滤器。

下面这张表整理出可以配合LPD工作的过滤器和在/etc/printcap里的他们的命令记录,以及要使用这些过滤器在使用lpr时要加什么参数:

文件格式

/etc/printcap里的命令

lpr下的参数

cifplot

cf

-c

DVI

df

-d

plot

gf

-g

ditroff

nf

-n

FORTRAN text

rf

-f

troff

rf

-f

raster

vf

-v

plain text

if

none-p-l

 

在我们的例子里,使用lpr -d意思就是说打印机会需要用到它的/etc/printcap文件的记录中由df命令所指定的过滤器。

不管别人怎么说,像FORTRAN文本或是plot这样的格式可能都已经用不到了。在你的机器上,可以安装其他格式的过滤器,如此一来你就可以将那些转换用的参数用来转换其他的格式。例如,假设你想直接打印Printerleaf文件(由Interleaf desktop publishing program产生的),而你不想打印plot文件。那么你可以用gf命令指定Printerleaf的转换用过滤器。同时告诉你的用户lpr -g命令就是打印Printerleaf文件

安装转换用的过滤器

转换用过滤器不属于FreeBSD本身的程序,因此它们可能被放在/usr/local目录下。通常我们可以将它们放在/usr/local/libexec目录下,因为这些程序是专门给LPD运行的,一般用户并不会需要去直接执行它们。

要使用转换用过滤器,只要将过滤器的路径放在/etc/printcap设置文件里用合适的命令指定即可。

在我们的例子里,我们将为名为bamboo的打印机设置一个DVI转换过滤器。以下是 /etc/printcap这个文件,其中打印机bamboo使用了df命令。

    #

#  /etc/printcap for host rose - added df filter for 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:fs#0x82000e1:xs#0x820:rw:\

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

:df=/usr/local/libexec/psdf:

DVI过滤器是一个shell脚本:/usr/local/libexec/psdf。以下是它的源代码:

#!bin/sh

#

#  psdf - DVI to PostScript printer filter

#  Installed in /usr/local/libexec/psdf

#

# Invoked by LPD when user runs lpr -d

#

exec /usr/local/bin/dvips -f | /usr/local/libexec/lprps “$@”

这个脚本在标准输入以过滤模式运行dvips(参数 -f),这就是要打印的工作。然后启动PostScrpt打印机过滤器lprps,同时也将LPD传给这个脚本的参数传给该过滤器(请阅读在PostScript打印机上打印纯文本)这一节。lprps将根据这些参数来统计打印的页数情况。

更多转换用的过滤器的例子

因为安装过滤器没有特别固定的方式,所以我们将多举一点例子来说明。这些例子也许可以作为日后你自己做过滤器时的参考,或是如果合适的话,也可以直接拿来用。

下面这个例子的脚本是一个将raster数据(其实只能给GIF文件使用)转成Hewlett Packard LaserJet III-Si打印机所能处理的过滤器:

#!/bin/sh

    #

#  hpvf - Convert GIF files into HP/PCL then print

#  Installed in /usr/local/libexec/hpvf

                    

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

giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \

&& exit 0 \

|| exit 2

它先将GIF格式转成portable anymap,然后再转成portable graymap,接着再转成portable bitmap,最后再转成与LaserJet/PCL兼容的数据。

下面是使用这个过滤器的/etc/printcap例子:

#

#  /etc/printcap for host 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:

下面的转换用过滤器是将由grpff排版系统所产生的troff数据转成让PostScript打印机bamboo所能打印的格式:

#!/bin/sh

#

#  pstf - Convert groff's troff data into PS then print.

#  Installed in /usr/local/libexec/pstf

#

exec grops | /usr/local/libexec/lprps “$@”

上面的脚本再一次使用lprps与打印机沟通。如果我们的打印机接在并口上,那么我们可以用下面这个脚本取代上面的脚本:

#!/bin/sh

#

#  pstf - Convert groff's troff data into PS then print.

#  Installed in /usr/local/libexec/pstf

#

exec grops

而如果要启用这个过滤器,我们在/etc/printcap里的添加下面这条记录:

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

这里有一个让熟悉FORTRAN的老手脸红的例子。这是一个让所有可以打印纯文本的打印机打出FORTRAN文本的过滤器。我们将在teak这台打印机上安装:

#!/bin/sh

#

# hprf - FORTRAN text filter for LaserJet 3si:

# Installed in /usr/local/libexec/hprf

#

   

printf “\033&k2G” && fpr && printf “\033&l0H” && exit 0

exit 2

我们只要在/etc/printcap文件里添加下面这行为teak这台打印机指定过滤器:

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

最后一个有点复杂的例子。我们要为先前提到的teak这台打印机新增一个可以将DVI转成激光打印机能处理的格式。首先,先修改/etc/printcap文件中关于DVI过滤器的位置:

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

现在,比较困难的部分:制作这个过滤器。我们需要一个能将DVI转成激光打印机PCL格式的程序。FreeBSD Ports Collections里有一个:dvi2xx。安装这个程序能给我们dvilj2p这个程序,它能将DVI转成LaserJet IIpLaserJet III以及LaserJet 2000兼容的格式。

dvilj2p这个程序使hpdf这个过滤器变得十分复杂,因为dvilj2p无法从标准输入取得数据。它得从文件中读数据。最糟糕的是,这个文件还必须以 .dvi结尾,所以用 /dev/fd/0作为标准输入是不行的。我们可以用符号连接产生一个暂时的文件名(以.dvi结尾)指向/dev/fd/0,然后强迫dvilj2p从标准输入读取数据。

另一个问题就是我们无法用/tmp来存放我们暂时的连接。符号连接被用户及组bin所拥有。而过滤器是以用户daemon的身份在执行。另外,/tmp目录设置了sticky bit。因此虽然过滤器建立了连接,但是因为这个连接属于其他的用户而无法删除。

因此,过滤器将会把符号连接建立在目前的目录下,也就是spooling目录(由 /etc/printcap文件中的sd命令所指定)。这是让过滤器来做这件事的最好地方,因为(通常)这里的可用空间会比/tmp下来得多。

所以,这个过滤器应该要这么写:

#!/bin/sh

    #

#  hpdf - Print DVI data on HP/PCL printer

#  Installed in /usr/local/libexec/hpdf

   

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

 

#

#  Define a function to clean up our temporary files.  These exist

#  in the current directory which will be the spooling directory

#  for the printer.

#

cleanup() {

rm -f hpdf$$.dvi

    }

   

#

#  Define a function to handle fatal errors: print the given message

#  and exit 2.  Exiting with 2 tells LPD to do not try to reprint the

#  job.

#

fatal() {

echo “$@” 1>&2

cleanup

exit 2

    }

   

#

#  If user removes the job LPD will send SIGINT so trap SIGINT

#  and a few other signals to clean up after ourselves.

#

trap cleanup 1 2 15

 

#

#  Make sure we are not colliding with any existing files.

#

cleanup

 

#

#  Link the DVI input file to standard input the file to print.

#

ln -s /dev/fd/0 hpdf$$.dvi || fatal “Cannot symlink /dev/fd/0”

 

#

#  Make LF = CR+LF

#

printf “\033&k2G” || fatal “Cannot initialize printer”

 

#

#  Convert and print.  Return value from dvilj2p does not seem to be

#  reliable so we ignore it.

#

dvilj2p -M1 -q -e- dfhp$$.dvi

 

#

#  Clean up and exit

#

cleanup

exit 0

自动转换:用过滤器转换外的另一种选择

上面这些过滤器完整地建立了你的打印环境,但是用户们必须自己决定要使用哪一个过滤器(对lpr命令下的参数)。如果你的用户们并不擅长于使用计算机,要它们自己选择适当的过滤器来使用可能会造成它们的困扰。更严重的是,万一使用到不正确的过滤器来转换格式,那么可能会让你的打印机浪费许多不必要的纸。

除了安装所有的转换用过滤器外,你也许会想要试试文本过滤器(默认的过滤器)自动扫描要打印的文件格式,同时自动呼叫其他的转换用过滤器做适当的转换。像file这样的工具对于这方面可能对这会有些帮助。然而,要区分出某些文件格式可能会有点困难。当然,你也可以提供专门转换这些格式的过滤器。

FreeBSD Ports Collection里有一个叫做apsfilter的文本过滤器可以进行自动扫描及转换。它可以分辨出纯文本,PostScript以及DVI文件,然后做适当的格式转换后再打出。

输出用过滤器

LPD spooling系统还支持一种我们还没有介绍的过滤器:输出用过滤器。输出用过滤器和文本过滤器一样,只有打印纯文本时才使用,但是它简单多了。如果你用了输出用过滤器但是没有用文本过滤器,那么:

             LPD在一份工作里将只执行一次输出用过滤器,而不是为每一个文件都执行一次。

             LPD不会提供任何辨认文件开始或结束的信息给输出用的过滤器

             LPD不会将用户的帐户及机器名称传给过滤器,因此它不能做统计的动作。事实上,它只有得到两个参数:

filter-name –w width –l length

其中width是由打印机设置里的pw命令设置的,而length是由pl命令设置的。请不要被输出用过滤器简单的特性误导了。如果你想要用输出用过滤器让一份工作里每个文件以一个不同的页开始,那输出用过滤器就无法工作。你应该用的是文本过滤器(也称为输入用过滤器),请参考安装文本过滤器这一节。此外,输出用过滤器实际上是较复杂的,因为它必须检查送给它的数据是否含有特殊的字符,并代替LPD送信号给自己。

如果你需要打印header page或是需要送控制字符等其他的初始化字符串使得可以打印header page,那么一个输出用过滤器是必须的。(但是如果你是为了要向用户收取打印header page的费用的话,那么这是没有用的。因为LPD不会将任何用户及机器的信息传给输出用过滤器。)

在一台简单的打印机上,LPD允许同时拥有输出用过滤器和文本或其他过滤器。在这个情况下,LPD会启动输出用过滤器只打印header page(请阅读Header page这一节)。然后,LPD会通过发送2个字节给这个过滤器:ASCII 001然后是ASCII 031,来希望输出用过滤器将自己停下来。当输出用过滤器看到这两个字节(031001)时,它将要送SIGSTOP信号给自己将自己停下来。当LPD运行完其他的过滤器后,它将通过发送SIGCONT信号将输出用过滤器重新激活。

如果只有输出用过滤器而没有文本过滤器,且LPD是要打印纯文本,那么LPD将会用输出用过滤器来做这些工作。按照以前的规定,输出用过滤器将会按顺序打印工作中的每个文件,而不需要换页或是移动其他纸张,这些结果可能不是你想要的。几乎在所有的情况下,你都需要一个文本过滤器。

我们以前介给过的程序:lpf,不但可以作为文本过滤器,也可以当作输出用过滤器使用。如果你需要快速的设置好输出用过滤器,但你不想自己写字节检测和发送信号的代码,那么你可以试试lpf。你也可以在shell脚本中使用lpf将必要的初始化代码送给打印机。

 

lpf:一个文本过滤器

FreeBSD里附带的/usr/libexec/lpr/lpf是一个文本过滤器(输入用过滤器)。它可以处理缩进(命令lpr -i),原封不动地打出数据(以lpr -l命令送出的工作),调整工作中的倒退字符及缩进,以及统计打印张数。它也可以拿来当作输出用过滤器。

lpf适合在许多打印环境下使用。虽然它无法送初始化顺序给打印机,但是我们可以很容易的写一个shell脚本送出需要的初始化值后再执行lpf

为了让lpf可以正确地统计打印张数,需要在/etc/printcap文件里为pwpl命令填入适当的值。它根据这些值来计算一张纸上可以打多少字,以及用户的工作需要用几张纸。关于打印机的统计问题,请阅读统计打印机使用情况这一节。

11.4.2 Header page

如果你有很多用户,他们使用不同的打印机,那么你也许会觉得需要打印header page

Header page,也称做bannerburst page,是用来辨认打出来的工作是属于谁的。通常header page以粗体的大字,可能再加上外框打出来的,以便用户能快速的在一堆打出的文档中找到自己的文档。不过header page的缺点就是每个工作都会多使用一张纸来打印header page。它的功用可能不会超过一分钟,而最后的下场都是丢进资源回收箱或是垃圾筒。(不过header page是一份工作一张,而不是一个文件一张,所以纸张的浪费可能没有你想象的那么严重)。

如果你的打印机可以直接打印纯文本的话,那么LPD可以自动为你的输出加上header page。如果你的打印机是PostScript的,那么你将会需要额外的程序来产生header page。请阅读在PostScript打印机上打印Header page这一节。

启用header page

在简单的打印机设置这节里,我们在/etc/printcap文件里利用设置sh以不打印header pagesh“suppress header”的意思)。如果某一台打印机要打印header page的话,那么只要将sh命令删除就行了。

看起来是不是很简单?

没错。你也许需要提供一个输出用过滤器将初始化字符送给打印机。下面是一个适用于Hewlett Packard PCL兼容打印机使用的输出用过滤器:

#!/bin/sh

#

#  hpof - Output filter for Hewlett Packard PCL-compatible printers

#  Installed in /usr/local/libexec/hpof

printf “\033&k2G” || exit 2

exec /usr/libexec/lpr/lpf

使用of命令来指定输出用过滤器的路径。请阅读输出用的过滤器这一节了解更多信息。

下面是一个为我们先前提到的打印机teak。在teak文件里设置要打印header page及输出用过滤器的例子:

    #

#  /etc/printcap for host 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:

现在,当用户用teak打印时,它们每个工作都会有一张header page。如果用户们愿意花时间亲自找出自己打的东西,那么他们可以用lpr -h命令设置不打出header page。请阅读Header Page参数以了解更多lpr的参数。

注意: LPD打完header page后会送出换页字符。如果你的打印机送出纸张的命令不是用这个字符,你可以在/etc/printcap文件中用ff命令指定。

控制header page 

通过启用header pageLPD将会产生出long header,这将用户,机器以及工作名称以大字打印在一整页上。这里有一个例子(kellyrose这台印机打印outline这个工作):

             

      

                                                                       

LPD在打印完这些后会送出换页字符,使得真正的打印工作会以新的一页开始打印(除非你在/etc/printcap文件为指定的打印机设置了sfsupress form feeds))。

如果你喜欢,LPD可以打印short header。只要在/etc/printcap文件里指定sbshort banner 即可。header page会像下面这个样子:

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

LPD默认是先打印header page再打印工作。如果你想要调换顺序,只要在/etc/printcap里指定hlheader last)即可。

统计打印

使用LPD内建的header page,那么在做打印统计时可能会遇到一个问题:header page得免费提供。为什么?

因为只有控制打印header page的输出用过滤器可以在打印header page时做打印统计,但是这个过滤器却没有用户及机器的数据或是一个统计数据文件,所以无法向用户收钱。我们也不能给文本过滤器或是转换用过滤器(这些过滤器可以直接取得用户及主机的信息)将统计结果都多加上一页,因为用户可以用lpr -h命令设置不要打印header page,而你可能就向这些用户多收了打印header page的费用。基本上,lpr -h是许多热爱环保的用户喜欢的参数,你无法鼓励别人不去使用它。

而修改每个过滤器使它们都可以打出header page也是不可行的(虽然这么做就可以正确地计费)。因为LPD并不会把用户有没有使用-h的信息传给过滤器,这么一来,即使用户下了lpr -h的命令要求不打印header page,它仍然会因为得到一张header page而多收取了这个费用。

那么,有什么好办法吗?

你可以:

             接收LPD的这个问题,不收取打印header page的费用。

             安装可以取代LPD的程序,比如说LPRng。请参考标准后台打印系统之外的选择这一节所介绍其他可以替代LPD的程序。

             撰写一个智能化的输出用过滤器。在打印header page及纯文本时,如果没有文字(输入用)过滤器,那么一般的输出用过滤器只做初始化打印机以及一些简单的字符转换工作。如果有设置文本过滤器,那么LPD只会用输出用过滤器来做打印header page的工作。事实上,输出用过滤器可以根据从LPD产生的header page数据来判断打印工作的用户及机器而加以收费。唯一的问题就是输出用过滤器会无法取得记录使用情况的记录文件(它不会从af命令传送文件名),但是如果你的记录文件是固定的,你可以直接硬编码进输出用过滤器。要用这种方式来处理的话,那么可以在/etc/printcap文件里使用shshort header)命令。上面的做法其实可能是很麻烦的,比较起来,用户应该会感谢让打印header page免费的系统管理员。

postscript打印机上打印header page

正如前面提到的,LPD可以为打印机产生合适的纯文本header page,当然,因为PostScript不能直接打印纯文本,所以LPD产生header page的工能在PostScript打印机上是用不到的——或是几乎用不到。

一个直接产生header page的方法是让所有的转换用过滤器及文本过滤器产生header page。过滤器可以让用户及机器的参数产生合适的header page。这个方法的缺点就是即使用户以lpr -h的方式送出工作,它们仍然会得到header page

让我们来试试这个方法。下面的脚本可以接收三个参数(用户名称,机器名称以及工作名称)并产生PostScript打印机能打印的header page

#!/bin/sh

#

#  make-ps-header - make a PostScript header page on stdout

#  Installed in /usr/local/libexec/make-ps-header

#

   

#

#  These are PostScript units 72 to the inch.  Modify for A4 or

#  whatever size paper you are using:

    #

page_width=612

page_height=792

border=72

   

#

#  Check arguments

#

if [ $# -ne 3 ]; then

echo “Usage: 'basename $0' <user> <host> <job>“ 1>&2

exit 1

fi

 

#

#  Save these mostly for readability in the PostScript below.

#

user=$1

host=$2

job=$3

date='date'

   

#

#  Send the PostScript code to stdout.

#

exec cat <<EOF

%!PS

   

%

%  Make sure we do not interfere with user's job that will follow

%

save

 

%

%  Make a thick unpleasant border around the edge of the paper.

%

$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

   

%

%  Display user's login name nice and large and prominent

%

/Helvetica-Bold findfont 64 scalefont setfont

$page_width $user stringwidth pop sub 2 div $page_height 200 sub moveto

$user show

 

%

%  Now show the boring particulars

%

/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

 

%

% That is it

%

restore

showpage

EOF

现在,每个转换用过滤器以及文本过滤器可以在打印前先呼叫这个脚本打印出header page,然后再打印工作的内容。我们之前提过的DVI转换用过滤器,可以被修改来产生一个header page

#!/bin/sh

#

#  psdf - DVI to PostScript printer filter

#  Installed in /usr/local/libexec/psdf

#

#  Invoked by LPD when user runs lpr -d

#

                 

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

 

注意这个过滤器如何从参数中取出用户名称及机器名称。虽然这个过滤器使用了一些不同的参数(请阅读过滤器的运作方式这一节),不过同样的技巧也可以应用在其他不同的过滤器上。

就如我们前面所提到的,这个方式很简单,只要给lpr命令禁用“suppress head page”选项(即-h选项)。如果用户想要少花些钱(如果打印header page要收费的话),那么它们将无法做到,因为每个过滤器都会为每个工作打印header page

如果要允许用户可以自己选择是否打印header pager,你得使用统计打印Header page这节介绍的技巧:写一个可以判断由LPD产生的header page的输出用过滤器,并由它输出PostScript打印机可以处理的数据。这么一来,如果用户以lpr -h送出工作,LPD将不会产生header page,且你的输出用过滤器也不会。否则,你的输出用过滤器将要根据LPD送出的数据然后以适当PostScript码将header page送给打印机处理。

如果你的PostScript打印机是接在串行端口上,那么你可以使用lprps里提供的输出用过滤器,psof,这个过滤器会做上面的动作。注意,psof这个过滤器将不会为header page计费。

 

11.4.3网络打印

FreeBSD支持网络打印:将工作送给远程的打印机处理。网络打印有两种类型:

             访问远程机器所安装的打印机。你在某一台机器上的串口或并口上接了一台打印机,然后你设置LPD使该台打印机可以接收网络上其他机器来使用。安装远程机器上的打印机这一节将告诉你如何设置。

             使用直接接在网络上的打印机。这种打印机通常有一个额外的网络接口,以及(或是取代掉原本的)传统的串口或并口。这种打印机可能有下列的工作方式:

             它可能可以使用LPD通信协议直接接收从其他机器送来的工作。在这种情况下,就和一般的机器上面运行LPD没什么不同。只要照着安装远程机器上的打印机这一节里的设置即可。

             它可能支持网络数据传输接口。这种情况下,你得将打印机连接到网络上的某一台机器上,然后让该机器负责接收工作以及在打印机间传送数据。请阅读使用网络数据传输接口的打印机里关于这类打印机安装的建议。

安装远程主机上的打印机

LPD spooling系统内建有将工作送给网络上其他执行LPD(或与LPD兼容)程序的机器打印的功能。这个功能让你可以将打印机安装在一台机器上,并让网络上其他的机器可以使用。这功能也可以直接配合支持LPD通信协议的网络接口打印机使用。

要使用远程打印,首先,我们要先按照简单的打印机设置在打印机服务器上将打印机设置好。然后参考高级打印机设置设置你所需要的参数,确定你的打印机可以和LPD配合运作。最后要确定本机在LPD的已授权使用远程机器列表里(请阅读限制来自远程打印机的工作这一节)。

如果你是使用兼容于LPD通信协议的网络接口打印机,那么下面讨论的打印机主机就是这台打印机,而打印机名称则是你为打印机设置的名称。请查阅随打印机或网络接口附带的手册来设置。

提示:如果你正在使用一个Hewlett Packard Laserjet打印机,那打印机名text将自动执行LFCRLD的转换,所以你将不需要这个hpif脚本。

接着,在其他要访问这些网络打印机的机器上,它们的/etc/printcap文件中用下面这些作一个记录:

1.         为你的网络打印机取个名字。为了简单起见,你可能会把打印机的名称及别名和打印机服务器取一样的名字。

2.         明确地将lp命令设置为空(:lp=:)。

3.         建立一个spooling目录同时将其位置以sd命令指定。LPD在将工作送给打印机服务器之前,会将这此工作放在这个目录下。

4.         rm命令指定打印机主机的名称。

5.         rp命令指定打印机主机上的打印机名称。

这些就足够了,你不需要在/etc/printcap文件里将转换用的过滤器列出,或是指定纸张的大小。

这儿有一个例子。主机rose有两台打印机,分别为bamboorattan。我们要让orchid这台机器上的用户可以使用这两台打印机。下面是orchid这台机器上的/etc/printcap设置文件(回想要求打印Header page这一节),这个文件里面已经设置teak这台打印机了,我们将要再加入两台连接在rose这台机器上的网络打印机:

#

#  /etc/printcap for host orchid - added remote printers on rose

#

   

#

#  teak is local; it is connected directly to orchid:

#

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 is connected to rose; send jobs for rattan to rose:

#

rattan|line|diablo|lp|Diablo 630 Line Printer:\

:lp=:rm=rose:rp=rattan:sd=/var/spool/LPD/rattan:

 

#

#  bamboo is connected to rose as well:

#

bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\

:lp=:rm=rose:rp=bamboo:sd=/var/spool/LPD/bamboo:

然后,我们只要在orchid建立spooling目录:

# 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

现在,orchid上的用户可以将数据交给rattanbamboo打印。例如,orchid上的用户可以输入

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

orchid上的LPD系统将会将工作拷贝到/var/spool/LPD/bamboo spooling目录下并注明它是要打印DVI的工作。当rose这台机器上给bamboo用的spooling目录有空间时,这两个LPD就会开始沟通将文件传给rose。然后这工作便进入rose的队列直到它被打出为止。而将DVI转换成PostScript(因为bambooPostScript打印机)的工作将会在rose这台机器上执行。

使用网络数据传输接口的打印机

如果你为打印机安装了一块网卡,通常有两种情况:这个接口具有后台打印系统的能力(较贵),或是只是拿来取代串口或并口(较便宜)。这一节要讨论的是如何使用较便宜的那种方式。如果你是选用较贵的接口,请参考前一节:安装远程机器上的打印机。

/etc/printcap文件的格式允许你指定使用串口或并口,以及(如果你使用串行端口)使用什么传输速率,哪一种流量控制,是否需要延长转换换行字符等等。但是,却没有一种方法可以指定以TCP/IP或是其他的网络连接端口与打印机连接。

如果要将数据送给这种网络打印机,你需要开发一种可以被文本及转换用过滤器调用的数据传输程序。这里有一个例子:netprint这个脚本可以读取标准输入的数据并将这些数据送到用网络连接的打印机。我们给netprint指定打印机主机名作为第一个参数,并连接到的端口号作为第二个参数。注意,这个程序只支持单向的传输(即从FreeBSD到打印机),而很多网络打印机都支持双向传输,你可能会想要使用这些功能(如取得打印机状态,统计打印情况等)。

#!/usr/bin/perl

#

#  netprint - Text filter for printer attached to network

#  Installed 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;

socketPRINTER &PF_INET &SOCK_STREAM $protocol

|| die “Can't create TCP/IP stream socket: $!”;

connectPRINTER $sockaddr || die “Can't contact $printer_host: $!”;

while <STDIN> { print PRINTER; }

exit 0;

然后我们可以在不同的过滤器里使用这个脚本。假设我们有一台连接在网络上的Diablo 750-N行式打印机。这台打印机用通信端口5100接收数据。这台打印机的名字叫做scrivener。以下是给这打印机使用的文本过滤器:

#!/bin/sh

#

#  diablo-if-net - Text filter for Diablo printer 'scrivener' listening

#  on port 5100.   Installed in /usr/local/libexec/diablo-if-net

#

exec /usr/libexec/lpr/lpf “$@” | /usr/local/libexec/netprint scrivener 5100

11.4.4限制打印机的使用

这一节讨论如何限制打印机的使用。LPD系统可以限制本机及远程使用打印机的用户,设置他们是否可以打印多份,打印工作大小的限制以及打印机队列的上限。

限制打印多份

LPD系统让用户可以很容易地将一个文件打印多份。举例来说,用户只要以lpr -#5命令就可以将这个工作里的每个文件都打印5份。不论这些文件里是什么东西。

如果你觉得打印多份会造成打印机的损坏,你可以在/etc/printcap设置文件里以sc命令关闭lpr命令的-# 参数。当用户尝试以 -# 参数送出工作时,它们将看到:

lpr: multiple copies are not allowed

注意,如果允许从远程使用你的打印机(请阅读安装远程机器上的打印机这一节),那么你得在远程机器上的/etc/printcap文件里也设置sc命令,否则用户仍然可以从远程的机器上要求打印多份。

这里有一个例子。这是rose这台机器的/etc/printcap设置文件。rattan这台打印机十分强大,所以我们允许在它上面打印多份,但是bamboo这台激光打印机有点弱小,因此我们在它上面设置了sc命令,不允许打印多份:

#

#  /etc/printcap for host rose - restrict multiple copies on 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/ttyd5:fs#0x82000e1:xs#0x820:rw:\

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

:df=/usr/local/libexec/psdf:

然后,我们也需要在orchid这台机器上的/etc/printcap设置文件里为网络打印机加上sc命令(同时,我们也不允许用户用teak这台打印机做打印多份的工作):

#

#  /etc/printcap for host orchid - no multiple copies for local

#  printer teak or remote printer 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:

使用sc命令以后,我们可以防止用户使用lpr -#,但是无法防止用户执行多次lpr,或是在一个工作里将同样的文件送好几次,像这样:

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

有很多方式可以防止这个滥用(包括忽略它),你可以自己尝试看看。

限制访问打印机

你可以使用UNIX的组机制及/etc/printcap设置文件的rg命令来控制谁可以使用哪台打印机。只要将允许访问打印机的用户放在某一个组中,然后用rg命令指定这个组名称即可。

在这个组之外的用户(包括root)将会看到“lpr: Not a member of the restricted group” 如果它们尝试使用被限制使用的打印机。和sc(禁止打印多份)一样,如果你觉得需要限制远程用户使用你的打印机,你也得在远程机器上的设置文件里设置rg命令。(请阅读安装远程机器上的打印机这一节)。

例如,我们将让所有人都可以使用rattan这台打印机,但是只有在artists组里的人可以使用bamboo这台打印机。下面是rose这台机器的/etc/printcap设置文件:

#

#  /etc/printcap for host rose - restricted group for 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:fs#0x82000e1:xs#0x820:rw:\

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

:df=/usr/local/libexec/psdf:

我们在这里不修改其他的/etc/printcap设置文件(比如说orchid机器上的)。这么一来,所有orchid机器上的用户都可以用bamboo来打印。通常这种情况是因为orchid上的用户不多且希望他们都可以访问打印机。

注意: 每个打印机只能使用一个组名称来做限制。

限制提交工作的大小

如果你有很多用户在使用打印机,你也许会想要限制用户能打印的文件大小。毕竟,在我们spooling目录所在的文件系统空间有限,而你得确保有足够的空间给其他的用户在打印时使用。

LPD让你可以用mx命令限制一个打印工作中的文件大小,以BUFSIZ区块为单位,每一块大小为1024字节。如果你将值设置为0,那么表示对文件大小没有限制。如果没有使用mx命令的话,那么默认的大小是1000个区块。

注意: 这些限制将会套用在打印工作中的文件,而不是整个打印工作的大小。

LPD不会拒绝接收一个文件大小超过你为打印机设置上限的文件。而会尽量将该文件小于上限的数据放入缓存并打出,而超出上限的数据则取消。这是不是一个正确的处理方式还有待争议。

让我们为我们举例的打印机rattanbamboo设置上限。既然这些艺术家的PostScript文件都蛮大的,我们将上限设置为5 MB。而我们在纯文本行式打印机上不做任何限制:

#

#  /etc/printcap for host rose

#

   

#

#  No limit on job size:

#

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:

   

#

#  Limit of five megabytes:

#

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:fs#0x82000e1:xs#0x820:rw:\

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

:df=/usr/local/libexec/psdf:

同样的,这些限制仅对本机用户有效。如果有人通过网络使用这些打印机,那么这些设置是不会产生作用的。你得在远程的/etc/printcap设置文件里也设置mx命令才行。请阅读安装远程机器上的打印机这一节以了解更多关于远程打印的信息。

有另一种更好的方法来限定远程打印机传送过来的打印工作大小。 请阅读限制来自远程打印机的工作这一节的说明。

限制远程打印机的工作

LPD spooling系统提供好几种方法来限制从远程传过来的打印工作:

主机限制

你可以用/etc/hosts.equiv/etc/hosts.lpd这两个文件来限制LPD接收哪些远程机器的要求。LPD会检查传出要求的机器是否列在这些文件中。如果没有的话,那么LPD会拒绝这些要求。

这两个文件的格式很简单:一行写一台机器名称即可。不过你得注意/etc/hosts.equiv这个文件也被ruserok通信协议所使用,因此会影响到像rshrcp等程序,所以你得小心的设置。

举例来说,rose/etc/hosts.LPD设置文件是这样的:

orchid

violet

madrigal.fishbaum.de

意思就是rose这台机器将会接收从orchidviolet,以及madrigal.fishbaum.de这三台机器送过来的要求。如果其他的机器想要来使用rose这台机器的LPD,那么LPD将会拒绝它们。

限制大小

你可以控制有多少空间得保留在spooling目录所在的文件系统上。只要在本机打印机的spooling目录上建立一个叫做minfree的文件就行了。而这个文件的内容是一个数字记录。当文件系统至少还有多少磁盘区块(512字节)的剩余空间时,才接收远程传来的打印工作。

这可以确保远程的用户不会将你的文件系统空间用完。而这块空间可以给本机用户一些保障:它们在文件系统剩余空间小于minfree文件里所指定的大小时,还是可以将打印工作送进打印队列。

举例来说,我们如果想要为bamboo设置minfree文件。我们得先查看/etc/printcap文件以找出这台打印机spooling目录的位置。下面是关于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:fs#0x82000e1:xs#0x820:rw:mx#5000:\

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

:df=/usr/local/libexec/psdf:

Spooling的目录是以sd命令设置。我们可以设置当那个文件系统的剩余空间在3 MB(即6144个磁盘区块)以上时,就接收远程来的打印工作:

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

限制用户

你可以在/etc/printcap里用rs命令设置哪些远程用户可以使用本机的打印机。当你为本机的打印机使用了rs以后,LPD只有在远程的用户名称在本机上也有同样的用户名称时,才会接收这个打印工作。否则LPD会拒绝接收该工作。

这个功能(举例来说)在不同部门共享打印机时,另一个部门的某些用户需要用到打印机。你只要在你的机器上为这些用户建立帐户,那么它们就可以在它们的部门里使用你的打印机。如果你只想要让它们使用你的打印机而不能使用你机器上的其他资源的话,那么你只要为它们建立“token”帐户,即没有home目录也没有可用的shell/usr/bin/false这样子即可。

11.4.5统计打印机的使用情况

纸张和墨水都是要钱的,管理也是需要花钱的——打印机常常因为运转负荷过重而发生故障,为何不向用户收取打印的费用呢?如果你打算收钱,你必须检查打印机,制定使用方式,以及制定打印一张纸(一英尺,一公尺,等等)要收多少钱。那么你要如何统计打印了多少呢?

不幸的是,LPD spooling系统在这方面的帮助并不大。统计的方法与你所使用的打印机,打印的格式,以及其他你想收费的项目有关。

如果要统计这个功能,你得修改打印机的文本过滤器(以对打印纯文本收费)或转换用过滤器(以对其他文件格式收费),以计算打印的张数或是如果无法计算的话,则向打印机查询打出的张数。你没有办法用输出用的过滤器来做统计的工作。请阅读过滤器这一节的说明。

一般来说,有两种统计的方式:

             定期统计是较常见的方式,也许是因为它比较容易。当有人打印工作时,过滤器将用户名称,机器以及打印的张数记录到一个记录文件里。每个月,每个学期,每年或是任何一段时间,你可以根据这些不同打印机的记录文件来结算每个用户所需的费用,并向他们收费。然后你就可以删除这些记录再重新开始计算。

             实时统计是较少用的方式,也许是因为它比较难设置。这个方法让过滤器马上计算出用户打印的数目并向他们收费。就像磁盘配额一样,这个统计是马上生效的。你可以提供一种方式供用户检查或调整他们的打印配额,以防止某些用户打印过量。但是这种方法需要一些维护数据库的程序代码以记录用户使用的配额。

LPD spooling系统可以很容易地支持上面两种情况:因为(大部分的时候)你得提供你的过滤器以及计算程序。这有一个好处就是你可以很有弹性地调整计算的方法。举例来说,不管你是使用定期统计还是实时统计,你可以选择要记录哪些信息:用户名称,机器名称,工作形态,打印的张数,纸张的大小,打印工作所花的时间等等。而你只要调整你的过滤器就可以了。

快速设置打印机的使用统计

FreeBSD提供两个程序让你可以快速设置好定期统计。它们是在文本过滤器:lpf那节所提到的lpf以及pac,一个可以从打印机打印记录文件读取并统计数据的程序。

在前几节(过滤器的运作方式),我们曾提到LPD会将记录文件名以参数的方式传给文本过滤器和转换用过滤器。这样过滤器就知道可以将计算结果记录到哪个文件里。这个文件名在/etc/printcap文件里是以af命令指定,如果不是以绝对路径来指定的话,那么这个文件将会放在相对应于spooling目录的位置下。

LPD会将纸张的宽度及高度传给lpf命令(由pwpl命令所指定)。lpf使用这些参数来计算将会用到多少张纸。而将文件送给打印机打印后,它会将这些结果记录在记录文件里。这些结果看起来是像这个样子的:

2.00 rose:andy

3.00 rose:kelly

3.00 orchid:mary

5.00 orchid:mary

2.00 orchid:zhang

由于lpf没有使用文件锁定的相关操作,因此每台打印机都要有独立的统计记录文件,否则两个lpf同时对同一个文件做写入的动作可能会使彼此的记录都不正确。而最简单的解决方式就是让不同的打印机在/etc/printcap设置文件里以af=acct命令指定不同的统计记录文件。这些acct文件将会分别放置在不同的spooling目录下。

当你准备要向用户收钱时,执行pac这个程序。只要将目录切换到你想收钱的打印机spooling目录下,然后打pac。你将会得到一份像下列的收费摘要:

    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

pac有下列参数可以使用:

-Pprinter

指定要处理哪一台打印机的统计数据。这个参数只有在/etc/printcap文件里的af命令是使用绝对路径时才有用。

-c

将输出的结果以费用排序,而不是以用户的名字排序。

-m

忽略记录文件里的机器名称。如果使用这个参数,那么alpha机器上的用户smithgamma机器上的用户smith将会被视为同一个用户。否则,它们会被视为不同的用户。

-pprice

计算时以每一页收取price元计算,而不是使用/etc/printcap里的pc所指定的价格或2分美金(默认的费率)计算。你可以用浮点数来指定price这个参数。

-r

颠倒排列的顺序。

-s

将计算的结果写到一个摘要文件里,同时清除统计记录文件的内容。

name ...

只为指定的用户打印统计信息。

pac默认的输出里,你可以看到不同机器上不同用户所打印的张数。如果你不在乎用户使用的机器(比如说用户可以用任何机器),那么你可以用pac -m产生下列的摘要输出:

      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

pac计算应缴纳的金额时,会使用/etc/printcap文件里pc命令所指定的费率(默认值为2美分)。即每一页或是每一英尺你想要收多少钱就是在这里指定。你可以在执行pac时以参数-p改变这个费率。不过-p的单位是元,而不是分,举例来说,

# pac -p1.50

将使打印每一页以15分计算。你可以用这个参数调整你所收取的费用。

最后,如果你使用pac -s将会把这些摘要信息存在一个文件里,这个文件的名称会和统计记录文件相同,不过文件名后面会再加上_sum。然后它会将统计记录文件清空。如果你再执行一次pac命令,那么它会先读取之前统计的结果,然后再加上从统计记录文件里所计算出来的结果。

如何统计有几页被打印?

为了要能精确统计打印的情况,你必须要知到每个工作用了几张纸。这是打印机使用情况统计最基本的问题。

对于纯文本的工作,这个问题并不难解决:你只要统计这个工作里有几行并知道你的打印机一张纸可以印几行就行了。别忘了考虑倒退字符以及因为同一行字符过多而换行的情况。

lpf文本过滤器(在文本过滤器:lpf这一节里介绍的)在做统计时会将这些情况都考虑进去。如果你要自己撰写有统计功能的文本过滤器,你可以参考lpf的源代码。

那么要如何统计其他格式的文件呢?

对于DVI转成LaserJetDVI转成PostScript,你可以让你的过滤器处理由dviljdvips的输出以判断一共转换了几页。你也许可以用类似的方式来处理其他的文件格式以转换程序。

但是这样的方法所计算出来的和打印机实际打出来的可能不大相同,举例来说,打印机可能会卡纸,用完色带碳粉或墨水,或是其他的故障-而这些用户仍然需要付费。

那么,我该怎么办?

只有一种方法肯定是可以做出精确的统计。买一台可以告诉你一共打出多少纸张的打印机,同时将它接在串行端口或是以网络连接。几乎所有的PostScript打印机都支持这个功能。当然其他种类的打印机也有支持的(如网络Imagen激光打印机)。为这些打印机修改你的过滤器,使得过滤器在打印完成后可以从打印机取得这些信息,同时也只根据这些记录来做统计。不需要做行数统计或是其他可能发生错误的计算方式。当然,你也可以大方的让所有的纸张打印输出都免费。

11.5使用打印机

这一节将告诉你如何在FreeBSD下使用打印机。这里有份用户级命令的概要:

lpr

打印工作

lpq

检查打印机队列

lprm

将工作从打印机队列中删除

也有系统维护使用的命令,lpc,用来控制打印机及其队列。在管理打印机这一节里有更详细的说明。

lprlprmlpq这三个命令都接收-P printer-name这个指定在 /etc/printcap文件里设定的打印机/队列的参数。允许你对不同的打印机作要求,删除,以及检查工作。如果你没有使用-P参数,那么这些命令将使用PRINTER环境变量所指定的打印机。如果你也没有PRINTER环境变量,那么这些命令则会对别名为lp的打印机指定动作。

此后,默认打印机指的就是以PRINTER环境变量设定的打印机或是当lp环境变量不存在时,别名为lp的打印机。

11.5.1打印工作

要打印文件,输入:

% lpr filename ...

这将把所有列出的文件以默认打印机打印。如果你没有指定任何文件,那么lpr将会从标准输入读入数据。下面这个例子将会打出一些重要的系统文件:

% lpr /etc/host.conf /etc/hosts.equiv

如果要指定以特定的打印机输出,输入:

% lpr -P printer-name filename ...

下面这个例子会将当前目录下的文件列表从名为rattan打印机输出:

% ls -l | lpr -P rattan

因为lpr命令以后没有指定任何一个文件,lpr将会从标准输入读入数据以打印出来,即由ls -l命令所产生的输出。

lpr命令有许多参数如控制输出格式,套用文件转换,一次打印出多份,等等。请参看 打印参数 这一节里有更详细的说明。

11.5.2检查打印工作

当你使用lpr打印时,一起送到LPD spooling系统的数据称为一个打印工作。每一台打印机都有一个打印工作队列,而你的打印工作和其他的打印工作一样在队列里等待打印。打印机会将先打印先送到的工作。

要显示默认打印机的队列,输入lpq即可。如果要指定打印机,请指定-P参数。例如

% lpq -P bamboo

这个命令会显示叫做bamboo的打印机队列。这里有一份lpq命令的输出例子:

bamboo is ready and printing

    Rank   Owner    Job  Files                              Total Size

    active kelly    9    /etc/host.conf /etc/hosts.equiv   88 bytes

    2nd    kelly    10   standard input                   1635 bytes

    3rd    mary     11   ...                                78519 bytes

上面显示一共有三个工作在bamboo的队列里。第一个工作由用户kelly送出,工作代码9。每一个工作都会有个唯一的工作代码。通常你可以忽略工作代码,但是如果你要取消某个工作时,你就需要知道工作号码。详情请参看删除队列这一节。

工作号码9里包含了两个文件。用lpr送多个文件将会被视为同一个工作。这是目前正在处理的工作(注意“Rank”栏标示的active),即打印机现在应该就在打印这个工作。第二个工作的数据是用lpr从标准输入接收数据的。而第三个工作是由用户mary送出的。这是一个较大的工作。而她要打印的文件因为太长而放不下,所以lpq命令只显示三个点。

lpq最前面的输出通常可以看出打印机现在在做什么(至少是LPD觉得打印机现在应该是在做什么)。

lpq命令可以使用-l参数以得到更详细的列表。这里有一个lpq -l的输出例子:

waiting for bamboo to become ready offline ?

    kelly: 1st                       [job 009rose]

           /etc/host.conf                    73 bytes

           /etc/hosts.equiv                  15 bytes

   

    kelly: 2nd                      [job 010rose]

           standard input                  1635 bytes

   

    mary: 3rd                                [job 011rose]

/home/orchid/mary/research/venus/alpha-regio/mapping 78519 bytes

11.5.3删除打印工作

如果你改变主意不想打印你的工作了,你可以用lprm命令把它们从打印队列中删除。通常你也可以用lprm把一个正在处理的工作删除,不过可能还是会打印出部分或是全部的文件。

要从默认打印机里删除工作,首先,用lpq找出工作代码,然后输入:

% lprm job-number

如果要从指定的打印机删除工作,那么用 -P参数。下列的命令从打印机bamboo的队列中删除工作号码为10的工作:

% lprm -P bamboo 10

lprm命令有一些常用的用法:

lprm -

将(默认打印机)里所有属于你的工作都删除。

lprm user

将(默认打印机)里所有属于用户user的工作都删除。只有超级用户可以删除其他人的工作,你只能删除你自己的工作。

lprm

如果不指定工作号码,用户名称或是-lprm将删除目前默认打印机正在处理的工作,但前提是这个工作必须是属于你的。超级用户可以删除任何目前正在处理的工作。

如果使用-P参数配合上面的常用用法,则上面的动作将对指定的打印机动作而不是对默认打印机。下列的命令将会删除目前用户在打印机rattan队列中的所有工作:

% lprm -P rattan -

注意: 如果你使用的是网络打印机,lprm将只允许你从输出工作的机器删除该工作。下面这些命令可以说明这个概念:

% lpr -P rattan myfile

% rlogin orchid

% lpq -P rattan

    Rank   Owner        Job  Files                          Total Size

    active seeyan    12       ...                           49123 bytes

    2nd    kelly      13   myfile                         12 bytes

% lprm -P rattan 13

rose: Permission denied

% logout

% lprm -P rattan 13

dfA013rose dequeued

cfA013rose dequeued

11.5.4在纯文本之外:打印选项

lpr命令提供控制格式输出,转换图形及其他文件格式,一次打出多份,工作处理方式等选项。这一节将一一介绍。

格式输出与转换选项

下列的lpr命令控制文件输出的格式。如果你的打印工作里没有纯文字或是你希望纯文字通过lpr处理后以特定的格式输出时,你可以使用这些选项。

举例来说,下面的命令从叫做bamboo的打印机将DVI文件(由TeX排版系统产生) fish-report.dvi打出:

% lpr -P bamboo -d fish-report.dvi

这些选项将套用这个工作里的每个文件,所以你不能把DVIditroff文件在同一个工作里一起处理,而要分两次工作用不同的转换选项。

注意: 这些选项除了-p-T需要为指定的打印机安装转换的过滤器外,其他的都不用。举例来说,选项-d需要安装DVI转换过滤器。转换用的过滤器这一节有较详细的说明。

c

打印cifplot文件。

d

打印DVI文件。

f

打印FORTRAN文本文件

g

打印plot数据。

i number

将输出缩进number个字符。 如果你省略number,则缩进8个字符。这个选项只有在某些转换用的过滤器上有效。

注意: 请不要在-i和数字之间加上空格。

l

原封不动的打出文本数据,包括控制字符。

n

打印ditroffdevice independent troff)数据。

p

在打印之前以pr格式化输出。请参看pr的联机手册了解更多的信息。

T title

title取代pr header中的文件名。这个选项只有在配合-p选项使用时才有效。

t

打印troff数据。

v

打印raster数据。

下面是一个以默认打印机打印格式化过的ls 联机手册的例子:

% zcat /usr/share/man/man1/ls.1.gz | troff -t -man | lpr -t

zcat命令将ls原始数据解压缩并传送给troff命令,将该数据格式化后以GNU troff格式输出给lpr送给LPD 后台打印系统处理。因为我们在使用lpr命令时使用了-t选项,所以后台打印系统在打印时会把GNU troff转换成默认打印机所能了解的格式。

工作处理方式选项

下列的选项将会让lpr告诉LPD以特别的方式处理工作:

# copies

将同一工作里的每个文件都打出copies份。系统管理员可以将这个选项关闭,以减低打印机的障碍并鼓励使用复印机。请参见限制打印多份这一节的说明。

这个例子将会从默认的打印机打出三份parser.c,然后打出三份parser.h

% lpr -#3 parser.c parser.h

m

完成打印工作后,便通知用户。如果使用这个选项,当打印工作完成后,LPD系统将会写信给你。在这封信中将会告诉你你的工作是否成功地打出或是有错误以及(通常会)告诉你错误的原因。

s

不要将要打印的文件拷贝到spooling目录,而只要以符号连接s的方式取代。

如果你要打印大的文件,你可考虑用这个选项。这可以节省你spooling目录的空间(否则spooling目录所在的文件系统可能会空间不足)。同时他也可以省下LPD将文件拷贝到spooling目录所需的时间。

这么做有一个缺点就是当打印还没结束时,你不能修改或删除打印中的文件,因为LPD在打印时还会用到原始文件。

注意: 如果你是用网络打印机打印,那么LPD还是会把你的文件拷贝到远程的机器,所以选项-s只有在本机上打印时才有用。

r

当你的文件已经拷贝到spooling目录时,或是用-s选项且打印完成时,就将原本的文件删除。请小心使用这个选项!

Header Page选项

有一些选项是设定lpr打印在header page上的文字。如果打印header page的话,那么这些选项就没有作用了。请参见Header page这一节以了解如何设定header page

-C text

header page上的机器名称用text替换。主机名称通常是提交打印工作的机器名称。

-J text

header上的工作名称用text替换。工作名称通常是一份打印工作里的第一个文件名称,如果你是从标准输入打印数据的话,那么将会是stdin

-h

不要打印header page

注意: 在某些机器上,由于header page产生的方式不同,这个选项可能会无效。请参看Header page这一节更详细的说明。

11.5.5管理打印机

作为打印机管理员,你必须安装,设定以及测试它们。你可以用lpc这个命令:

             打开或停止打印机。

             开启或关闭他们的队列。

             重新安排队列里工作的顺序。

我们得先知道的一个术语:如果一个打印机已经停止工作了,它将不会将队列里的任何东西打出来。用户仍然可以将工作送过来,但是这些工作将会在队列里等待直到打印机开始工作或是队列被清空。

如果队列被关闭了,那么没有用户(除了root之外)可以将工作送给打印机。只有已经开启队列的打印机可以接收其他人将工作送过来。一个打印机可以为一个已经关闭的队列开始工作。在这种情况下,原本存在队列中的工作将会一一地被打印直到没有工作为止。

通常,拥有root权限的用户才可以用lpc命令。一般的用户只能用lpc命令来查询打印机工作以及重新启动当掉的打印机。

以下是一份lpc的命令列表。大部份的命令都需要指定printer-name以指定要对哪一台打印机下命令。printer-name也可以用all表示所有排在/etc/printcap里的打印机。

abort printer-name

取消目前的工作,同时也停止打印机工作。如果队列被关闭,用户仍然可以送工作给打印机。

clean printer-name

将打印机spooling目录中的旧文件删除。有时候LPD可能没有把打印完的工作从spooling目录中删除,尤其是当打印的工作发生错误时或是有其他命令将其中止时。这个命令将会找出这些不该存在于spooling目录中的文件并将他们删除。

disable printer-name

关闭队列以停止接收新工作。如果打印机并未停止工作,那么队列中剩余的工作将会继续打印直到队列中没有工作为止。关闭队列后,root仍然可以继续送工作给打印机。

这个命令在你测试一台新打印机或是新的过滤器时特别有用:你可以将队列关起来然后以root测试打印的工作。其他用户则无法将工作送过来,除非你测试完毕后将队列以enable命令打开。

down printer-name message

这个命令等于是disable后再接着stop命令。其中message是当有用户以lpq检查打印机队列或是以lpc status命令检查打印机状态时所显示的信息。

enable printer-name

将打印机队列打开。这样用户就可以将工作送给打印机,但是只有在打印机已经开始工作后,队列里的工作才会被打出来。

help command-name

command-name命令的说明打出。如果没有指定command-name,那么将会打出所有可用的命令。

restart printer-name

重新启动打印机。如果因为某些情况使得LPD当掉了,一般的用户可以用这个命令让打印机重新开始工作。但是他们无法用这个命令让由stopdown命令停止的打印机开始工作。restart命令等于abort再接着start命令。

start printer-name

让打印机开始工作。打印机会将队列里的工作打出。

stop printer-name

停止打印机工作。打印机将会先完成目前的工作然后停止打印队列中的任何工作。打印机停止工作后,用户仍然可以把工作送给一个未关闭的队列中。

topq printer-name job-or-username

将打印机printer-name队列中工作代号为job或是属于用户username的工作移到队列的最前面。在这个命令里,你不可以将all填在printer-name上指定所有的打印机。

up printer-name

这是和down命令相对的指令。等于是start后再接着enable命令。

lpc能以选项的方式接收上面的命令。如果你不输入任何命令,lpc将会进入交谈模式,在这里你可以一直输入命令直到你以exit命令,quit命令或是输入文件结尾字符为止。

11.6标准后台打印系统之外的选择

如果你读完了这篇文章,现在应该已经彻底了解了FreeBSD提供的LPD spooling系统。不过你可能觉得这个系统有些缺点,因此你可能会想到:除此之外还有哪些spooling系统(可以配合FreeBSD使用)?

LPRng

LPRng指的是下一代的LPR”LPRng是将PLP完全重写。Patrick PowellJustin Mason PLP的主要维护人)一起合作开发LPRngLPRng的网站是http://www.astart.com/lprng/LPRng.html

11.7疑难解答

lptest做过简单的测试后,你可能会遇到下面的问题。

打印机打了一阵子,但是并没有输出任何结果。

打印机打出上面所列的东西,但是没多久就停了。这时,你可能需要按打印机上的PRINT REMAININGFORM FEED钮才看得到输出的结果。

如果是这种情况的话,打印机在打印前可能在等待是否还有更多的资料要打印。要解决这个问题,你可以让文本过滤器送出FORM FEED字符(或是其他需要的字符)给打印机。这个动作让打印机打出目前打印机缓存区里的资料。同时也确定每个工作的最后一页可以完整的输出,使得下个工作不会从前一个工作的最后一页中间输出。

下面这个shell脚本替换/usr/local/libexec/if-simple。将工作送给打印机后,会再送出一个换页字符:

#!/bin/sh

    #

# if-simple - Simple text input filter for lpd

# Installed in /usr/local/libexec/if-simple

    #

# Simply copies stdin to stdout.  Ignores all filter arguments.

# Writes a form feed character \f after printing job.

/bin/cat && printf “\f” && exit 0

exit 2

打出了阶梯效应

你的结果可能是这个样子:

!”#$%&'()*+-./01234

“#$%&'()*+-./012345

#$%&'()*+-./0123456

这时你已经成为因为换行字符冲突而产生阶梯效应的受害者。UNIX风格的操作系统只使用ASCII10line feed LF)作为换行字符。MS-DOSOS/2以及其他的操作系统使用两个字符ASCII10以及ASCII13 (称作carriage returnCR)。很多打印机使用MS-DOS的表示法来代表换行字符。

当你用FreeBSD打印时,你的文件只用line feed字符换行。当打印机看到一个line feed字符时,将纸卷了一行,仍然从同一个位置继续往后打印。这就是为什么要用carriage return字符的原因:将下一个字的打印位置移到纸张的最左边。

FreeBSD希望你的打印机可以:

打印机收到CR       打印机打印CR

打印机收到LF             打印机打印CR + LF

有一些方法可以达到这个目地:

1.    用打印机上的开关或控制面板设置这些字符的处理方式。请查阅你的打印机手册并做正确的设置。

注意: 如果你的计算机安装了除FreeBSD外的操作系统,你也许得常常重新设置打印机处理CRLF的设置。因此,你可能会希望使用下面其中之一的方法:

2.    FreeBSD的串口驱动程序自动将LF转换成CR+LF。当然,你的打印机只能在串行口上。如果要打开这个功能,只要在 /etc/printcap设置文件里为你的打印机用fs关键词设置CRMOD这个位即可。

3.    送一个句柄给打印机告诉它暂时把LF字符做额外的处理。请参阅你的打印机手册以了解你的打印机是否支持此功能。如果你找到适用的句柄,修改你的文本过滤器先送出这些句柄,再送出要打印的工作。

下面这个文本过滤器的例子是使用Hewlett-Packard PCL代码。先让打印机将LF视为LFCR处理,再送出工作。接着,再送出一个换页符以完成上一页的工作。这个过滤程序应该可以工作在大部分的Hewlett-Packard打印机上。

#!/bin/sh

    #

# hpif - Simple text input filter for lpd for HP-PCL based printers

# Installed in /usr/local/libexec/hpif

    #

# Simply copies stdin to stdout.  Ignores all filter arguments.

# Tells printer to treat LF as CR+LF.  Ejects the page when done.

printf “\033&k2G” && cat && printf “\033&l0H” && exit 0

exit 2

而下面这个/etc/printcap的例子是设置一台叫做orchid计算机。它在第一个并口连接了一台叫做teakHewlett-Packard LaserJet 3Si打印机。同时,它使用了上面的脚本作为文本过滤器:

    #

#  /etc/printcap for host orchid

    #

teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\

:lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\

:if=/usr/local/libexec/hpif:

每一行都重迭在一起

打印机从不换行,把每一行都印在同一行上。这个问题和上面的阶梯效应相反。而且也较罕见。FreeBSD用来换行的LF字符被当成CR字符使得打印机一直回到纸张的最左边开始打印但却不换行。使用打印机上的设置开关或是控制面板设置使LFCR字符这样被处理:

打印机收到

打印机打印

CR

CR

LF

CR + LF

打印机会少打某些字

打印时,打印机在一行中会少打某些字。这个情况在打印时可能会变得愈来愈严重,有越来越多的字打不出来。这是因为打印机接收资料的速度无法跟上计算机通过串行端口送资料的速度(这个问题在并口打印机上应该不会发生)。有两种方法可以解决这个问题:

1.    如果打印机支持XON/XOFF流量控制,在FreeBSD里可以用fs关键词来设置TANDEM位。

2.    如果打印机支持carrier流量控制,用fs关键词来设置MDMBUF位。确定连接打印机及计算机的连接线可以配合carrier流量控制使用。

3.    如果打印机不支持任何一种流量控制,那么在fs关键词里试着设置NLDELAY TBDELAYCRDELAYVTDELAY以及BSDELAY等位的组合以适当地延迟数据送到打印机。

打出乱码

打印机打出看不懂的符号,而不是我们期望中的数据。这通常是因为序列打印机的通信参数设置不正确而造成的。再检查一次br关键词所设置的传输速率,fsfc关键词所设置的奇偶校验。同时也检查打印机是否也使用与/etc/printcap文件相同的设置。

没有任何动作发生

如果没有任何反应,那么可能是FreeBSD的问题而不是硬件的问题。为你的打印机在/etc/printcap设置文件里设置记录文件(使用lf命令)。下面的例子是用lfrattan这台打印机设置记录文件:

rattan|line|diablo|lp|Diablo 630 Line Printer:\

:sh:sd=/var/spool/lpd/rattan:\

:lp=/dev/lpt0:\

:if=/usr/local/libexec/if-simple:\

:lf=/var/log/rattan.log

然后试着再打印一次,并检查记录文件(在我们的例子里,是/var/log/rattan.log这个文件)里是否出现错误信息。然后根据错误信息来解决你的问题。

如果你没有用lf指定记录文件,LPD默认使用/dev/console