---
title: 第9章 プリンタの利用
part: パートII. 日々の生活
prev: books/handbook/kernelconfig
next: books/handbook/linuxemu
showBookMenu: true
weight: 12
params:
  path: "/books/handbook/printing/"
---

[[printing]]
= プリンタの利用
:doctype: book
:toc: macro
:toclevels: 1
:icons: font
:sectnums:
:sectnumoffset: 9
:partnums:
:source-highlighter: rouge
:experimental:
:images-path: books/handbook/printing/

ifdef::env-beastie[]
ifdef::backend-html5[]
:imagesdir: ../../../../images/{images-path}
endif::[]
ifndef::book[]
include::shared/authors.adoc[]
include::shared/mirrors.adoc[]
include::shared/releases.adoc[]
include::shared/attributes/attributes-{{% lang %}}.adoc[]
include::shared/{{% lang %}}/teams.adoc[]
include::shared/{{% lang %}}/mailing-lists.adoc[]
include::shared/{{% lang %}}/urls.adoc[]
toc::[]
endif::[]
ifdef::backend-pdf,backend-epub3[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]
endif::[]

ifndef::env-beastie[]
toc::[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]

[[printing-synopsis]]
== この章では

FreeBSD は古いインパクトプリンタから最新のレーザープリンタまで幅広いプリンタが利用でき、 実行しているアプリケーションから高品質な印刷出力が行えます。

FreeBSD はネットワーク上のプリンタサーバとして動作するように設定することもできます。 この機能は、他の FreeBSD コンピュータや、Windows(R) や Mac OS(R) ホストから印刷ジョブを受け取ることができます。 FreeBSD は印刷ジョブを 1 つずつ処理することを保証します。 また、どのユーザやマシンが最も多く印刷しているかの統計を取り、 どの印刷物が誰の物か表示する "バナー" ページの作成などを行うことができます。

この章を読めば以下のことがわかります。

* FreeBSD プリントスプーラの設定方法。
* 入力ドキュメントをプリンタが扱える印刷フォーマットへ変換するなどといった、 特別な印刷ジョブを別に取り扱うための印刷フィルタのインストール方法。
* 印刷物へのヘッダやバナーの適用方法。
* 他のコンピュータに接続されたプリンタで印刷する方法。
* ネットワークに直接接続されたプリンタで印刷する方法。
* 印刷ジョブの上限サイズや特定のユーザからの印刷拒否といった、 プリンタの制限の制御方法。
* 印刷の統計とプリンタの使用状況の取得方法。
* 印刷問題のトラブルシューティング方法。

この章を読み始める前に以下を済ませておいてください。

* 新しいカーネルの設定とインストール方法について理解すること (crossref:kernelconfig[kernelconfig,FreeBSD カーネルのコンフィグレーション])。

[[printing-intro-spooler]]
== はじめに

FreeBSD でプリンタを使うために、それらを LPD スプーリングシステム、 または単に LPD としても知られる Berkeley ラインプリンタスプーリングシステムで動作するように設定できます。 これは FreeBSD での標準的なプリンタ制御システムです。 この章では、LPD を紹介し、 その設定方法について説明します。

あなたがすでに LPD やその他のプリンタスプーリングシステムに詳しいのなら、 <<printing-intro-setup,基本的な設定>> まで読み飛ばしてもかまいません。

LPD はホストのプリンタに関するあらゆることを制御します。 ここで言う制御としては、次のことがあげられます。

* ホストに接続されたプリンタ、 あるいはネットワーク上の他ホストに接続されたプリンタに対するアクセス制御を行ないます。
* ファイルをプリントする要求に対して許可を与えます。 この要求は特に__ジョブ__と呼ばれています。
* 各々のプリンタの__キュー__を管理することにより、 複数のユーザがあるプリンタに対して同時にアクセスすることを防ぎます。
* __ヘッダページ__ (__バナー__または __バースト__ページとしても知られています) をプリントすることができます。 これにより、 プリントアウトの山の中から自分がプリントしたジョブを見つけやすくなります。
* シリアルポートに接続したプリンタ用に通信パラメータを管理します。
* ネットワーク経由で他のホスト上の LPD スプーラにジョブを送ることができます。
* 様々なプリンタ言語やプリンタの能力に応じてジョブの形式を整えるため、 特別なフィルタを起動することができます。
* プリンタの使用に対して課金を行なうことができます。

設定ファイル ([.filename]#/etc/printcap#) を通して、専用のフィルタプログラムを用いることにより、 多種多様なプリンタ機器に対して、上述の機能の全部または一部を LPD システムに行なわせることができます。

[[printing-intro-why]]
=== どうしてスプーラを使うべきなのか

あなたのシステムを利用するのがあなた一人だけだとしても、 スプーラは有用ですし、使用すべきです。その理由は以下のとおりです。

* LPD はジョブをバックグラウンドで処理します。 データがプリンタに送信されるまで待つ必要がなくなります。
* LPD ではジョブをフィルタを通してプリントすることが簡単にできます。 これにより、印刷物のヘッダに時刻や日付を入れたり、 特別なファイル形式 (TeX の DVI ファイルなど) をプリンタが処理できる形式に変更することができ、 これらの作業を手動で行なう必要がなくなります。
* プリント処理を行なうフリー、 または商用のプログラムのほとんどは、 システムのスプーラとやりとりするように作られています。 スプーリングシステムをセットアップすることで、 今後加えるかもしれない、あるいは、 すでに持っている別のソフトウェアをより簡単にサポートすることができるでしょう。

[[printing-intro-setup]]
== 基本的な設定

LPD スプーリングシステムを用いてプリンタを使用するためには、 プリンタ機器と LPD 用ソフトウェアの両方を準備する必要があります。 本文書では次の二段階のレベルに分けて説明をします。

* プリンタを接続する方法、 プリンタにどのように通信するかを LPD に指示する方法や、 プレインテキストをプリンタで印字する方法については、 <<printing-simple,プリンタの簡単な設定>>をご覧ください。
* 様々な形式のファイルを印字する方法、 ヘッダページを印字する方法、 ネットワーク経由でプリンタに印字する方法、 プリンタを制御する方法、 プリンタの使用に対する課金を行なう方法については<<printing-advanced,プリンタ設定上級編>>をご覧ください。

[[printing-simple]]
=== プリンタ設定導入編

この節では、プリンタ機器やプリンタを使用するための LPD 用ソフトウェアを設定する方法について述べます。 この節の概要は次のとおりです。

* <<printing-hardware,プリンタ機器の設定>>では、 プリンタをコンピュータに接続するためのヒントがいくつか書かれています。
* <<printing-software,ソフトウェアの設定>>では、 LPD のスプーラ設定ファイル ([.filename]#/etc/printcap#) の設定方法について書かれています。

データをプリンタに送るのにコンピュータのローカルインタフェースではなく、 ネットワークプロトコルを使用する場合は、 <<printing-advanced-network-net-if, ネットワークにおけるデータストリームインタフェースを持つプリンタ>>をご覧ください。

この節のタイトルは "プリンタ設定導入編" ですが、 実際の設定はかなり複雑です。 プリンタをコンピュータに接続し、 LPD スプーラを起動させることは一番困難な作業です。 ヘッダページを出力させたり課金したりするオプションの設定は、 一度プリンタがうまく動くようになればとても簡単です。

[[printing-hardware]]
==== プリンタ機器の設定

この節では、プリンタに PC を接続するための様々な方法について説明しています。 ここでは、ポートやケーブルの種類、 FreeBSD がプリンタとの通信に必要なカーネルコンフィグレーションについても言及しています。

もしプリンタが既に接続されていて、 他のオペレーティングシステム上でプリンタからの印字に成功している場合は、 <<printing-software,ソフトウェアの設定>>まで読み飛ばすことが多分できるでしょう。

[[printing-ports]]
===== ポートとケーブル

今日 PC 用に売られているプリンタには通常、 次の 3 つのインタフェースのうち、どれか 1 つ以上がついてきます。

* __シリアル__インタフェース (RS-232 または COM ポートとも呼ばれます) は、 コンピュータにあるシリアルポートを使ってプリンタにデータを送信します。 シリアルインタフェースはコンピュータ業界で共通して使用されています。 そのケーブルは容易に手に入りますし、簡単に自作することもできます。 シリアルインタフェースの場合は時々、 特別なケーブルや何か複雑な通信方式選択の設定が必要になることがあります。 ほとんどの PC のシリアルポートは通信速度が最大で 115200 bps であり、 大きな画像を印刷するのには実用的ではありません。
* __パラレル__インタフェースではプリンタにデータを送信するために、 コンピュータにあるパラレルポートを使用します。 パラレルインタフェースは PC 業界ではよく使われており、 RS-232 シリアルよりも速いです。 ケーブルの入手は容易ですが、 自作するのはシリアルよりも困難です。 パラレルインタフェースには通常、通信方式の選択はなく、 設定は極めて単純です。
+ 
パラレルインタフェースは "セントロニクス" インタフェースとして知られています。 これは、プリンタ用のコネクタタイプとして採用された後に名付けられました。
* USB インタフェースは、Universal Serial Bus (汎用シリアルバス) の略で、パラレルや RS-232 シリアルよりさらに速く動作します。 ケーブルは単純で安価です。USB は、印刷目的には RS-232 シリアルやパラレルよりも向いていますが、UNIX(R) システムでは十分対応されていません。 この問題を回避する手としては、多くのプリンタがそうですが、 USB とパラレルの両方のインタフェースを備えたプリンタを購入することが挙げられます。

パラレルインタフェースでは、普通は (コンピュータからプリンタへの) 単方向通信のみを行なうのに対して、 シリアルおよび USB インタフェースは双方向通信を行ないます。 FreeBSD でも IEEE1284 準拠のケーブルを使えば、 最近のパラレルポート (EPP や ECP) とプリンタの多くで双方向通信を行なうことができます。

パラレルポート経由のプリンタとの双方向通信には、 通常 2 つの方法のどちらかが使われます。一つ目の方法は、 プリンタが使用しているプロプライエタリな言語を話す FreeBSD 用に作成されたプリンタドライバを使うものです。 これはインクジェットプリンタではよく使われる方法で、 インクの残量やその他の状態の情報を知らせるのに使えます。 二つ目の方法は、プリンタが PostScript(R) に対応している時に使われます。

PostScript(R) ジョブは、実際にはプリンタに送信されるプログラムです。 印字作業を行う必要は必ずしありませんし、 プログラムの結果を直接コンピュータに返してもよいのです。 PostScript(R) プリンタでは双方向通信を使って PostScript(R) プログラムのエラーや紙づまりといった問題をコンピュータに報告します。 ユーザはそれらの情報を知りたいと思うかも知れません。 また、PostScript(R) プリンタで課金作業をもっとも効率よく行なうためには、 双方向通信が必要となります。 この方法ではまず、プリンタの現在のページカウント (起動してから今まで何枚の紙を印字したか) の情報を得ます。 次に、ユーザのジョブを実行し、終了後、再びページカウントを得ます。 この二つの数を差によって、 課金対象となる紙の枚数を知ることができるのです。

[[printing-parallel]]
===== パラレルポート

プリンタをパラレルインタフェースを使って接続する場合は、 セントロニクスケーブルでプリンタとコンピュータを接続してください。 詳しい説明はプリンタやコンピュータに付属する説明書に書かれているはずです。

その際、 どのパラレルポートを使用したかを覚えておいてください。 FreeBSD では最初のポートは [.filename]#ppc0#、 二番目が [.filename]#ppc1# であり、 三番目以降も同様に続きます。 プリンタのデバイス名にも同じ形式が使われており、 最初のパラレルポートに接続されたプリンタは [.filename]#/dev/lpt0# などとなります。

[[printing-serial]]
===== シリアルポート

シリアルインタフェースを使ってプリンタを使う場合は、 適切なシリアルケーブルでプリンタとコンピュータを接続してください。 詳しい説明はプリンタ、コンピュータ、あるいは両方に付属する説 明書に書かれているはずです。

"適切なシリアルケーブル" が良くわからないときは、 次のどれかを試してみてください。

* __モデム__用ケーブルでは、 それぞれのピンは他方のコネクタの対応するピンと線でつながっています。 このタイプのケーブルは "DTE-DCE" 間ケーブルとしても知られています (訳注: 日本ではストレートケーブルという名前で売られています)。
* __ヌルモデム__用ケーブルでは、 あるピンは対応するピンとを接続していますが、 あるピン (たとえば、データ送信用とデータ受信用のピン) が交差して接続したり、 いくつかのピンは内部で短絡していたりします。 このタイプのケーブルは、 "DTE-DTE" 間ケーブルと呼ばれています (訳注: 日本ではクロスケーブルという名前で売られています)。
* A __シリアルプリンタ__用ケーブルは、 ある特定のプリンタで必要とされるものです。 ヌルモデムケーブルと似ていますが、 内部で短絡させる代わりに、 ある信号を他方側に送るために使用しています。

この他に、 プリンタ用の通信パラメータを設定する必要があります。 通常、プリンタのフロントパネルや DIP スイッチによって制御します。 コンピュータとプリンタの双方で設定できる最高の通信速度 [bps] (ビット/秒、 __ボーレート__と示されているときもある) を選んでください。そして、データビット (7 または 8)、 パリティ (偶/奇/なし)、ストップビット (1 または 2) を選んでください。 そして、フローコントロールの有無 (制御なし、または XON/XOFF ("イン・バンド" または "ソフトウェア" フローコントロールとも呼ばれる)) を選びます。 以下に続くソフトウェアの設定のために、 ここでの設定を覚えておいてください。

[[printing-software]]
==== ソフトウェアの設定

本節では FreeBSD の LPD スプーリングシステムで印字をおこなうために 必要となるソフトウェアの設定について説明しています。

本節の概要は次のようになります。

[.procedure]
====
. プリンタで使用するポートのために、必要があれば、 カーネルの書き変えをおこないます。「<<printing-kernel,カーネルの変更>>」で、 このためにしなくてはならないことを説明しています。
. パラレルポートを使用している場合は、 パラレルポートのための通信モードを設定します。 詳細は、 「<<printing-parallel-port-mode, パラレルポートの通信モードを設定する>>」 で説明しています。
. オペレーティングシステムからプリンタにデータが送ら れているかをテストします。「<<printing-testing,プリンタとの通信状況を調べる>>」で、 どのようにテストするかの提案をいくつかおこなっています。
. ファイル[.filename]##/etc/printcap##を変更し、 LPD の設定をおこないます。 この節で、どのように変更するかを説明しています。
====

[[printing-kernel]]
===== カーネルの変更

オペレーティングシステムのカーネルの コンパイルをおこなうことによって、 指定されたデバイスが機能するようになります。シリアル、 または、パラレルインタフェースをプリンタで使用する場合、 必要なデバイスがこの指定の中に含まれていなくてはなりません。 したがって、 必要なデバイスがカーネルに組み込まれていない場合、 追加のシリアル、または、パラレルポートをサポートするために、 カーネルの再コンパイルが必要となるかもしれません。

シリアルポートが現在使用しているカーネルで サポートされているかどうかを調べるためには、 次のように入力します。

[source,shell]
....
# grep sioN /var/run/dmesg.boot
....

ここで、_N_ はシリアルポートの番号を示し、この番号は 0 から始まります。 次のような出力があった場合、 カーネルはそのポートをサポートしています。

[source,shell]
....
sio2 at port 0x3e8-0x3ef irq 5 on isa
 sio2: type 16550A
....

パラレルポートが現在使用しているカーネルで サポートされているかどうかを調べるためには、 次のように入力します。

[source,shell]
....
# grep ppcN /var/run/dmesg.boot
....

ここで、_N_ はパラレルポートの番号を示し、この番号は 0 から始まります。 次のような出力があった場合、 カーネルはそのポートをサポートしています。

[source,shell]
....
ppc0: <Parallel port> at port 0x378-0x37f irq 7 on isa0
ppc0: SMC-like chipset (ECP/EPP/PS2/NIBBLE) in COMPATIBLE mode
ppc0: FIFO with 16/16/8 bytes threshold
....

上記の出力が得られない場合、プリンタを使うため、 オペレーティングシステムにパラレル、または、 シリアルポートを認識し、使用できるようにするためには カーネルを変更する必要があります。

シリアルポートをサポートさせるには、「crossref:kernelconfig[kernelconfig, FreeBSD カーネルのコンフィグレーション]」の節をご覧く ださい。パラレルポートをサポートさせる場合も、その節と、 _あわせて_、 この節に続く節もご覧ください。

[[printing-parallel-port-mode]]
==== パラレルポートの通信モードを設定する

パラレルインタフェースを使用している場合、FreeBSD では、 割り込み駆動型にするか、 プリンタとの通信の状況をカーネルに監視させるかのいずれかを選択できます。 FreeBSD の汎用プリンタデバイスドライバ (man:lpt[4]) は man:ppbus[4] システムを利用しています。 これは man:ppc[4] ドライバを使ってパラレルポートのチップセットを制御します。

* GENERIC カーネルでは__割り込み駆動__方式がデフォルトになっています。 この方式では、 オペレーティングシステムはプリンタがデータを受け付けられるかどうかを調べるために、 IRQ ラインを一つ使用します。
* __監視__方式では、 オペレーティングシステムにプリンタがもっとデータを受け付けられるかどうかを繰り返し尋ねるように指示します。 そして、受け付けるという応答を受けたとき、 カーネルはさらなるデータを送信します。

割り込み駆動方式は一般的にいくらか高速になりますが、貴重な IRQ ラインを一つ消費します。 HP の新しいプリンタの一部には、明らかに何かしらのタイミングの問題 (まだ正確にはわかっていません) で割り込みモードでは正常に動作しないものがあると言われています。 これらのプリンタにはポーリングモードが必要になります。 どちらかうまく機能する方を使ってください。 一部のプリンタはどちらの方式でも動作しますが、 割り込みモードでは苦痛を感じるほど低速です。

通信モードを設定するためには 2 つの方法があります。 1 つはカーネルを変更することで、もう一つは man:lptcontrol[8] プログラムを使用する方法です。

__カーネルを設定することによって、 通信モードを変更する。__

[.procedure]
====
. カーネルコンフィグレーションファイルを変更します。 `ppc0` のエントリを探してください。 2 番目のパラレルポートを設定するときは、代わりに `ppc1` を使います。 以下、3 番目のポートは `ppc2` となっていきます。

** 割り込み駆動方式にする場合は、 [.filename]#/boot/device.hints# ファイルの以下の行を編集して、 _N_ を適切な IRQ 番号に置き換えてください。
+
[.programlisting]
....
hint.ppc.0.irq="N"
....
+ 
カーネルの設定ファイルには man:ppc[4] ドライバも入れなければなりません。
+
[source,shell]
....
device ppc
....
+
** ポーリングモードを使用する場合は、 [.filename]#/boot/device.hints# ファイルの以下の行を削除してください。
+
[.programlisting]
....
hint.ppc.0.irq="N"
....
+ 
場合によっては、これだけでは FreeBSD でポートをポーリングモードにするには十分ではないことがあります。 多くの場合これは man:acpi[4] ドライバと併せて動作します。 これはデバイスのプローブとアタッチを行うので、 プリンタポートへのアクセスモードを制御できます。 問題を修正するために man:acpi[4] の設定を確認してください。
+
. ファイルをセーブし、config プログラムを起動し、 カーネルの構築、インストールをおこないます。そして、 リブートしてください。詳細は、「crossref:kernelconfig[kernelconfig, FreeBSDカーネルのコンフィグレーション]」を参照 してください。
====

man:lptcontrol[8] __で通信モードを設定する場合__

[.procedure]
====

. `lptN` をイベント駆動方式に設定する場合は、 次のように入力します。
+
[source,shell]
....
# lptcontrol -i -d /dev/lptN
....
+
. `lptN` を監視方式に設定する場合は、次のように入力します。 
+
[source,shell]
....
# lptcontrol -p -d /dev/lptN
....
====

これらのコマンドを [.filename]#/etc/rc.local# ファイルに追加 しておくと、システムをブートする度に通信モードを設定する ことができます。詳細については、 man:lptcontrol[8] をご覧ください。

[[printing-testing]]
==== プリンタとの通信状況を調べる

スプーリングシステムの設定に進む前に、オペレーティング システムがプリンタにデータを送ることに成功しているかどうか を確かめるべきでしょう。これにより、印字がうまくいかないと き、プリンタとの通信が問題なのか、スプーリングシステムが問 題なのかを分けて調べることがかなり容易になります。

プリンタをテストするためには、 プリンタに何かのテキストを送 信してみます。送信した文字をすぐに印字してくれるプリンタに は、man:lptest[1] コマンドを使うと有用です。このコマンドは印 字可能な 96 文字の ASCII 文字すべてを 96 行生成します。

PostScript(R) (または他の言語に対応した) プリンタの場合 は、もっと巧妙なテストが必要になります。次のような、簡単な PostScript(R) プログラムを使えば十分でしょう。

[.programlisting]
....
%!PS
100 100 moveto 300 300 lineto stroke
310 310 moveto
/Helvetica findfont 12 scalefont setfont
(Is this thing working?) show
showpage
....

上の PostScript(R) コードはファイルに保存し、 以降の節で例として示されているように利用することができます。

[NOTE]
====
このドキュメントでプリンタ用言語を参照するときは、 PostScript(R) のような言語を仮定しており、Hewlett Packard の PCL は考慮していません。PCL は非常に機能的なの ですが、 プレインテキストにエスケープシーケンスを混ぜること ができます。PostScript(R) ではプレインテキストを直接印字 することはできません。 このような種類のプリンタ言語に対しては、 特別な対応をおこなわなければなりません。
====

[[printing-checking-parallel]]
===== パラレルポートのプリンタとの接続を調べる

この節では、FreeBSD がパラレルポートに接続されたプリ ンタと通信できているかどうかを調べる方法について説明し ています。

_パラレルポートのプリンタをテストするために_

[.procedure]
====

. man:su[1] コマンドで `root` になります。
. プリンタにデータを送ります。

** プリンタがプレインテキストを印字できる場合、 man:lptest[1] コマンドを使います。 次のように入力してください。
+
[source,shell]
....
# lptest > /dev/lptN
....
+ 
ここで、_N_ はパラレルポートの番号で、番号は 0 から始まります。
** プリンタが PostScript(R) か他のプリンタ 言語を使用している場合、そのプリンタに簡単なプロ グラムを送信してください。次のように入力します。 
+
[source,shell]
....
# cat > /dev/lptN
....
+ 
そして、一行一行、 プログラムを__慎重に__入力して 下さい。RETUREN または ENTER キーを入力してしま うと、その行は編集できなくなります。プログラムの 入力が終わったら、CONTROL+D か、あなたが設定して いるファイル終了のキーを押してください。
+ 
もしくは、プログラムを入力したファイルがある 場合は、次のように入力してください。
+
[source,shell]
....
# cat file > /dev/lptN
....
+ 
ここで、_file_ はプログラムが格納されていて、 プリンタに送信するファイルの名前です。
====

これで何かが印刷されるはずです。 印字されたテキストがおかしくても心配は無用です。 それについては、後で修正します。

[[printing-checking-serial]]
===== シリアルポートのプリンタとの接続を調べる

この節では、FreeBSD がシリアルポートに接続されたプリ ンタと通信できているかどうかを調べる方法について述べられ ています。

_シリアルポートのプリンタをテストするために_

[.procedure]
====

. man:su[1] コマンドで `root` になります。
. [.filename]#/etc/remote# ファイルを編集します。次のエントリを加えてください。 
+
[.programlisting]
....
printer:dv=/dev/port:br#bps-rate:pa=parity
....
+ 
ここで、_port_ シリアルポート (`ttyu0`、 `ttyu1` など) のデバイスエントリで、 __bps-rate__は プリンタとの通信の転送速度[bit/秒]、 __parity__はプリ ンタとの通信で必要とされるパリティ (`even`、`odd`、 `none`、 ``zero``のいずれか) を表わしていま す。
+ 
次の例は、 プリンタをシリアルケーブルでパリティなし、転送速度 19200 bps で第 3 番目のシリアルポートに接続した場 合です。
+
[.programlisting]
....
printer:dv=/dev/ttyu2:br#19200:pa=none
....
+
. man:tip[1] コマンドでプリンタと接続します。 次のように入力してください。
+
[source,shell]
....
# tip printer
....
+ 
これがうまくいかなかった場合は、 [.filename]##/etc/remote##を編集して、 [.filename]##/dev/ttyuN## の代わりに [.filename]##/dev/cuaaN## を試してみてください。
+
. プリンタにデータを送ります。
+
** プリンタがプレインテキストを印字できる場合、 man:lptest[1] コマンドを使います。 次のように入力してください。
+
[source,shell]
....
% $lptest
....
+
** プリンタが PostScript(R) か他のプリンタ言語を使用している場合、 そのプリンタに簡単なプログラムを入力します。 一行一行、プログラムを__慎重に__入力してください。 バックスペースキーや他の編集用のキーは、 プリンタの制御コードに割り当てられているかもしれません。 プログラムが終了したことをプリンタに伝えるための特別なファイル終了キーを 入力する必要があるかもしれません。 PostScript(R) プリンタの場合、 `CONTROL+D` を入力します。
+ 
もしくは、プログラムを入力したファイルがある場合は、 次のように入力してください。
+
[source,shell]
....
% >file
....
+ 
ここで、_file_ はプログラムが格納されているファイル名です。 man:tip[1] コマンドでファイルを送信した後は、 ファイル終了を表わすキーを入力する必要があります。
====

これで何かがプリントされることでしょう。 印字されたテキ ストがおかしくても心配しなくても構いません。 それについては、後で修正します。

[[printing-printcap]]
==== スプーラに許可を与える: [.filename]#/etc/printcap# ファイル

ここまでで、プリンタはコンピュータに接続され、(必要なら) プリンタと通信できるようにカーネルを変更し、 簡単なデータをプリンタに送信することができているはずです。 これで、LPD にプリンタへのアクセスを 制御させる設定をおこなう準備が整いました。

LPD の設定は [.filename]#/etc/printcap# を編集することでおこないます。 LPD スプーリングシステムは スプーラが使われる毎にこのファイルを参照します。 そのため、ファイルを更新するとすぐにその変更が反映されます。

man:printcap[5] ファイルの書式は簡単です。 [.filename]#/etc/printcap# の編集はお好みのテキストエディタをお 使いください。このファイルの書式は、 [.filename]#/usr/shared/misc/termcap# や [.filename]#/etc/remote# といった他のケイパビリティファイルと一致しています。 この書式 についての詳細な情報については man:cgetent[3] をご覧ください。

スプーラの単純な設定法は、 次のステップでおこないます。

[.procedure]
====
. プリンタに名前 (と簡単な別名 2 ～ 3 個) を付け、それを [.filename]#/etc/printcap# ファイルに記述します。 これについては、「<<printing-naming, プリンタに名前を付ける>>」 を参照してください。
. `sh` の項目を追加することで、 ヘッダページの出力を禁止します (デフォルトは許可)。 これについては、「<<printing-no-header-pages, ヘッダページの印字を禁止する>>」 を参照してください。
. スプール用のディレクトリを作成し、その位置を `sd` 項目で指定します。これについては、 「<<printing-spooldir, スプーリングディレクトリの作成>>」 を参照してください。
. プリンタを使用するために [.filename]#/dev# エントリを設定し、[.filename]#/etc/printcap# の `lp` 項目でそのエントリを指定します。 これについては、「<<printing-device, プリンタデバイスの特定>>」 を参照してください。 プリンタをシリアルポートに接続した場合は、 `ms#` の項目を設定する必要があります。こちらについては、 「<<printing-commparam, スプーラのための通信パラメータの設定>>」 を参照してください。
. プレインテキスト用の入力フィルタのインストールをおこないます。 「<<printing-textfilter,テキストフィルタのインストール>>」 を参照してください。
. man:lpr[1] コマンドで何かを印字することで設定のテストをおこないます。 <<printing-trying,印字してみよう>> と <<printing-troubleshooting,トラブルシューティング>> を参照してください。
====

[NOTE]
====
PostScript(R) プリンタのような、 プリンタ言語を使用しているプリンタには、 プレインテキストを直接印字させることができません。 上にアウトラインを示し、 以下の節で説明する簡単な設定方法の説明では、 そのようなプリンタを設置している場合は、 プリンタが認識できるファイルだけを印字の対象としているという 仮定をしています。
====

多くの場合、 利用者はシステムに設置されているプリンタすべてで プレインテキストが印字できることを期待しています。 印字作業をおこなうために LPD のインタフェースを利用するプログラムでも、 通常、そのような仮定を置きます。 プリンタ言語を使用するプリンタを設置しており、 そのプリンタ言語で記述されたジョブと、 _これに加えて_、 プレインテキストのジョブも印字できるようにしたいならば、 上で示した簡単な設定方法に加えて、 さらなる設定をおこなうことを強くお勧めします。すなわち、 自動的にプレインテキストから PostScript(R) (もしくは、 他のプリンタ言語) に変換するプログラムをインストールしてください。「<<printing-advanced-if-conversion, プレインテキストのジョブを PostScript(R) プリンタで印字する>>」 で、それをどのようにおこなえばよいのかが説明されています。

[NOTE]
====
日本語を印字したい場合は、プリンタ言語を使用し ていない「日本語プリンタ」についても、 プリンタ固有のエスケープシーケンスを送る必要があります。 また、漢字コードをプリン タが設定しているものに変換したりする必要があり、 各プリンタ毎に、日本語用のフィルタが必要になります。
====

[[printing-naming]]
===== プリンタに名前を付ける

最初の (簡単な) ステップで、プリンタの名前を考えます。 プリンタには別名をいくつか付けることもできるので、 機能的な名前 でも風変わりな名前でもどちらを選んでもまったく 問題はありません。

少なくとも1つのプリンタには、 [.filename]#/etc/printcap# の中で、 `lp` という別名を持たせるべきでしょう。 この名前はデフォルトのプリンタ名になっています。 ユーザが環境変数 `PRINTER` を設定しておらず、 かつ、LPD コマンドのコマンドラインで プリンタの名前が指定されていない場合、`lp` がデフォルトのプリンタ名となり、 そのプリンタに出力されます。

それから、これは共通の慣習ですが、 プリンタの最後の別名には、 メーカーやモデル名を含むプリンタの完全な名称をつけることに なっています。

名前と別名のいくつかを決めたら、 [.filename]#/etc/printcap# ファイルに設定します。 プリンタ名は一番左のカラムから書き始めます。 別名はそれぞれ縦棒によって区切られ、 最後の別名の後ろにコロンを置きます。

次の例では、2 台のプリンタ (Diablo 630 ラインプリンタと Panasonic KX-P4455 PostScript(R) レーザライタプリンタ) が定義 されている [.filename]#/etc/printcap# のスケルトンを記しています。

[.programlisting]
....
#
#  /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` という名前と別名として、`line`、 `diablo`、`lp` そして `Diablo 630 Line Printer` が付けられています。別名とし て `lp` があるので、このプリンタはデフォルトのプリンタとなっ ています。2 番目は `bamboo` と名付けられ、 別名として、`ps` と `PS`、`S`、 `panasonic`、`Panasonic KX-P4455 PostScript v51.4` が付けられています。

[[printing-no-header-pages]]
===== ヘッダページの印字を禁止する

LPD スプーリングシステムでは、 デフォルトでジョブ毎に __ヘッダページ__を印字します。 ヘッダページにはジョブを要求したユーザ名、 ジョブが送られたホスト名、そして、ジョブの名前が素晴 らしい大きな文字で印字されています。 残念なことに、この余分なテキストすべてが、 簡単なプリンタ設定法のデバッグの際に紛れ込んできてしまいます。 このため、ヘッダページの出力を禁止しておきます。

ヘッダページの出力を禁止するには、 [.filename]#/etc/printcap# にあるプリンタのエントリに `sh` の項目を追加します。次に、`sh` を加えた [.filename]#/etc/printcap# の例を示します。

[.programlisting]
....
#
#  /etc/printcap for host rose - no header pages anywhere
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
        :sh:

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

この書式を正しく使うための注意をしておきます。 最初の行は左端のカラムから始めます。 それに続く行は字下げします。最後の行以外のすべての行は、 行末にバックスラッシュを記述します。

[[printing-spooldir]]
===== スプーリングディレクトリの作成

スプーラの簡単な設定の次のステップでは、 __スプーリングディレクトリ__を作成します。 プリンタに送られるジョブは、 その印字が終了するまでこのディレクトリに置かれます。また、 他のたくさんのスプーラもこのディレクトリにファイルを置きます。

様々な事情によりスプーリングディレクトリは、通常、慣例 として [.filename]#/var/spool# の下に置きます。 また、スプーリングディレクトリの内容は バックアップをする必要はありません。 man:mkdir[1] によってディレクトリを 作るだけでスプーリングディレクトリの復旧は完了します。 

スプーリングディレクトリの名前は、これも慣例ですが、 次のようにプリンタの名前と同じにします。

[source,shell]
....
# mkdir /var/spool/printer-name
....

しかしながら、ネットワーク上に使用可能なプリンタがたく さんあるならば、LPD で印字するための専用のディレクトリにスプーリングディレクトリを置きたくなるかもしれません。 例に出てきたプリンタ `rattan` と `bamboo` について、この方式を採用すると、 次のようになります。

[source,shell]
....
# mkdir /var/spool/lpd
# mkdir /var/spool/lpd/rattan
# mkdir /var/spool/lpd/bamboo
....

[NOTE]
====
各ユーザが印字するジョブのプライバシを守りた いと考えているならば、スプーリングディレクトリを保護し て、これを誰からでもアクセスできないようにしたいと思う かもしれません。スプーリングディレクトリは、 `daemon` ユーザと `daemon` グループに所有され、 読み込み、書き込み、検 索可能であり、他からはアクセスできないようにするべきで す。例題のプリンタに対して、次のようにすることにしましょ う。

[source,shell]
....
# 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
....

====

最後に、[.filename]#/etc/printcap# ファイルで、 これらのディレクトリの位置を LPD に伝える必要があります。 スプーリングディレクトリのパス名は `sd` 項目で指定します。

[.programlisting]
....
#
#  /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:
....

プリンタ名が最初のカラムから始まっており、 そのプリンタに関して記述される他の項目は字下げされていること、 各行がバックスラッシュで終わっていることに注意してください。

`sd` によりスプーリングディレクトリが指定されていない場合、 スプーリングシステムは [.filename]#/var/spool/lpd# をデフォルト値として使用します。

[[printing-device]]
===== プリンタデバイスの特定

<<printing-hardware,プリンタ機器の設定>> の節では、FreeBSD でプリンタとの通信に使用されるポートおよび [.filename]#/dev# ディレクトリ内のエントリを特定します。 そして、LPD にその情報を伝えます。 印字するジョブを受け取ると、スプーリングシステムは、 (プリンタにデータを渡す義務がある) フィルタプログラムに代わって指定されたデバイスをオープンします。

[.filename]#/etc/printcap# ファイルで `lp` 項目を使って [.filename]#/dev# エントリを記入します。

ここでの例では、`rattan` は 1 番目のパラレルポートに、`bamboo` は 6 番目のシリアルポートに接続されていることにしましょう。 このとき、[.filename]#/etc/printcap# には 次のようになります。

[.programlisting]
....
#
#  /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/ttyu5:
....

[.filename]#/etc/printcap# でプリンタの `lp` 項目が指定されていない場合は、 LPD はデフォルトとして [.filename]#/dev/lp# を使用します。[.filename]#/dev/lp# は、現在の FreeBSD には存在していません。

設置したプリンタがパラレルポートに 接続されている場合は、 「<<printing-textfilter, テキストフィルタのインストール>>」 まで読み飛ばしてください。 そうでない場合は、次節の説明に続いてください。

[[printing-commparam]]
===== スプーラのための通信パラメータの設定

シリアルポートにプリンタを接続した場合、 LPD は、プリンタにデータを送信するフィルタプログラムに代わり、 通信速度やパリティ、 その他のシリアル通信パラメータを設定することができます。 このことによる利点は、

* [.filename]#/etc/printcap# を編集するだけで、 様々な通信パラメータを試してみることができます。 フィルタプログラムを再コンパイルする必要はありません。
* スプーリングシステムで、 シリアル通信の設定が異なっているかもしれない複数のプリンタに 同じフィルタプログラムを使うことが可能になります。

次の [.filename]#/etc/printcap# の項目で、 `lp` で指定された デバイスのシリアル通信パラメータを制御できます。

`br#bps-rate`::
デバイスの通信速度を _bps-rate_ に設定します。 ここで、_bps-rate_ は 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200 [bit/秒] のいずれかです。

`ms#stty-mode`::
デバイスをオープンした後にターミナルデバイスのオプションを設定します。 利用できるオプションについては man:stty[1] を参照してください。

`lp` で指定されたデバイスをオープンするとき、 LPD は `ms#` で指定されたデバイスの特性を設定します。 特に関係があるのは、`parenb`, `parodd`, `cs5`, `cs6`, `cs7`, `cs8`, `cstopb`, `crtscts`, `ixon` モードです。 これらは man:stty[1] のマニュアルページで説明されています。

例題のプリンタで6番目のシリアルポートに接続された プリンタの設定を追加してみましょう。 通信速度は 38400bps に設定します。 モードとして、`-parenb` でパリティ無し、 `cs8` で 8 ビットキャラクタ、 `clocal` でモデム制御無し、 そして `crtscts` でハードウェアフロー制御を設定します。

[.programlisting]
....
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:
....

[[printing-textfilter]]
===== テキストフィルタのインストール

ここまでで、 プリンタにジョブを送るために使うテキストフィルタを LPD に設定する準備が整いました。 __テキストフィルタ__とは、 __入力フィルタ__としても知られていますが、 印字するジョブがあるときに LPD が起動するプログラムです。 LPD がプリンタのためにテキストフィルタを起動するとき、 LPD はフィルタの標準入力からプリントするジョブを入力し、 フィルタの標準出力に項目 `lp` で指定されたプリンタデバイスを接続します。フィルタは、 標準入力からジョブを読み込み、 プリンタのための必要な変換をおこなった後、 その結果を標準出力に出力する、 これにより印字がなされることを期待されています。 テキストフィルタについての更に詳しい情報については、「<<printing-advanced-filters, フィルタはどのように機能しているか>>」 をご覧ください。

ここでの簡単なプリンタ設定では、 プリンタにジョブを送るため、`/bin/cat` を実行するだけの簡単なシェルスクリプトで間に合います。 FreeBSD に標準で付属している `lpf` というフィルタでは、バックスペース文字を使った 下線引きの動作をおこなう文字ストリームをうまく扱うことができない プリンタのための代替処理をおこなってくれます。 もちろん、 他のどんなフィルタプログラムを使っても構いません。 フィルタ [.filename]#lpf# については、「<<printing-advanced-lpf,テキストフィルタ lpf>>」で詳しく説明します。

最初に、簡単なテキストフィルタであるシェルスクリプト [.filename]#/usr/local/libexec/if-simple# を作ってみましょう。 次のテキストをお好みのテキストエディタでファイルに 書き込んでください。

[.programlisting]
....
#!/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
....

そして、このファイルを実行可能にします。

[source,shell]
....
# chmod 555 /usr/local/libexec/if-simple
....

LPD にこのテキストフィルタを使うことを設定するためには、 [.filename]#/etc/printcap# に `if` 項目を使って指定します。これまでの [.filename]#/etc/printcap# の例のプリンタ 2 台に、 このフィルタを加えてみましょう。

[.programlisting]
....
#
#  /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/ttyu5:ms#-parenb cs8 clocal crtscts:\
        :if=/usr/local/libexec/if-simple:
....

[NOTE]
====
[.filename]#if-simple# スクリプトのコピーが [.filename]#/usr/shared/examples/printing# ディレクトリにあります。
====

===== LPD の起動

man:lpd[8] は `lpd_enable` 変数に従って [.filename]#/etc/rc# から実行されます。この変数の デフォルト値は `NO` です。まだ そうしていなかったならば

[.programlisting]
....
lpd_enable="YES"
....

の行を [.filename]#/etc/rc.conf# に追加して 計算機を再起動するか、そのまま man:lpd[8] を 起動してください。

[source,shell]
....
# lpd
....

[[printing-trying]]
===== 印字してみよう

簡単な LPD 設定も終わりにたどり着きました。 残念ながら、設定はこれでおしまいというわけではありません。 なぜなら、さらに、設定をテストし、 すべての問題点を解決しなくてはならないからです。 設定をテストするために、 何かを印字してみましょう。 LPD システムで印字をするためには、 man:lpr[1] コマンドを使います。このコマンドは、 印字するためのジョブを投入する働きをします。

man:lpr[1] コマンドを 「<<printing-testing, プリンタとの通信状況を調べる>>」で紹介した、 あるテスト用のテキストを生成してくれる man:lptest[1] プログラムと一緒に使うこともできます。

_簡単な LPD 設定のテスト_

次のように入力してください。

[source,shell]
....
# lptest 20 5 | lpr -Pprinter-name
....

ここで、_printer-name_ は [.filename]#/etc/printcap# で指定したプリンタ名 (もしくはその別名) です。デフォルト のプリンタを使用する場合は、 `-P` 引数を付けないで man:lpr[1] を打ち込んでください。もう一度述べますが、 PostScript(R) を期待しているプリンタをテストするならば、 man:lptest[1] を使う代わりに PostScript(R) で書かれた プログラムをプリンタに送ってください。 プログラムを送るためには、プログラムをファイルに格納して、 `lpr file` と打ち込みます。

PostScript(R) プリンタの場合、 送信したプログラムによる結果が得られるでしょう。 man:lptest[1] を使った場合は、 以下のような結果が見られるでしょう。

[source,shell]
....
!"#$%&'()*+,-./01234
"#$%&'()*+,-./012345
#$%&'()*+,-./0123456
$%&'()*+,-./01234567
%&'()*+,-./012345678
....

更にプリンタをテストしたい場合は、 (言語ベースのプリンタのための) もっと大きなプログラムを送信するか、 引数を変えて man:lptest[1] を実行します。たとえば、`lptest 80 60` で、それぞれ 80 文字の行を 60 行生成します。

プリンタがうまく動かなかった場合は、次の節、「<<printing-troubleshooting, トラブルシューティング>>」をご覧ください。

[[printing-advanced]]
== プリンタ設定上級編

この節では、特殊な形式のファイルを印字するためのフィルタ、 ヘッダページ、ネットワーク越しのプリンタへの印字、そして、 プリンタ使用の制限や課金について説明しています。

[[printing-advanced-filter-intro]]
=== フィルタ

LPD は、ネットワークプロトコル、キュー、アクセス制御などの 印刷にかかわるさまざまな点を扱いますが、 __実際の__作業のほとんどは __フィルタ__によっておこなわれています。 フィルタは、プリンタと通信し、 プリンタのデバイス依存性や特殊な要求を扱うプログラムです。 簡単なプリンタ設定では、 プレインテキストのためのフィルタをインストールしました。 このプレインテキストフィルタは、 ほとんどのプリンタで機能する極めて単純なものでした (「<<printing-textfilter, テキストフィルタのインストール>>」を参照)。

しかしながら、形式変換やプリンタ課金、特定のプリンタの癖、 など をうまく利用するためには、 フィルタがどのように機能するかという ことを理解しておくべきです。これらの側面を扱うことは、 最終的には、フィルタの責任であるからです。 そして、これは悪い情報ですが、ほとんどの場合において、 __あなた自身__が フィルタを供給する必要があるということです。また都合のよいことには、 たくさんのフィルタが一般的に利用できるということです。 もしフィルタがなかったとしても、 普通はフィルタを作るのは簡単です。

FreeBSD にも、プレインテキストを印字させることができる [.filename]#/usr/libexec/lpr/lpf# というフィルタが 1 つ付いています (このフィルタはファイルに含まれるバックスペースやタブを扱います。 また、課金をすることもできますが、 できることはこれだけしかありません)。 いくつかのフィルタとフィルタの構成要素は FreeBSD Ports Collection にもあります。

この節で述べることは次の通りです。

* 「<<printing-advanced-filters, フィルタはどのように機能しているか>>」では、 印字の過程におけるフィルタの役割を概説します。 この節を読むことで、LPD がフィルタを使うときに、"見えないところで" 何が起こっているかが理解できるでしょう。このことを知っておくと、 プリンタそれぞれに様々なフィルタをインストールしたときに 遭遇するかもしれない問題を予期したり、 デバッグするときに役立つでしょう。
* LPD は、すべてのプリンタがデフォルトでプレインテキストを印字できることを期待しています。 これは、プレインテキストを直接印字できない PostScript(R) (または他の言語対応の) プリンタで問題になります。「<<printing-advanced-if-conversion, プレインテキストのジョブを PostScript(R) プリンタで印字する>>」 で、 この問題を克服する方法について述べます。 PostScript(R) プリンタをお持ちの方は、 この節をお読みになることをおすすめします。
* PostScript(R) は様々なプログラムのための有名な出力形式です。 PostScript(R) のコードを直接書いてしまう人すらいます。 残念ながら、PostScript(R) プリンタは高価です。「<<printing-advanced-ps,非 PostScript(R) プリンタによる PostScript(R) のシミュレート>>」節では、PostScript(R) データを__非 PostScript(R) プリンタ__に受けつけさせ、印字させるために、 どのようにしてプリンタ用のテキストフィルタをさらに変更すればよいのか、 ということについて説明しています。PostScript(R) プリンタを持っていない方は、 この節をお読みになることをおすすめします。
* 「<<printing-advanced-convfilters, 変換フィルタ>>」では、 図形や組版データといった特定のファイル形式を、 プリンタが理解できる形式へ変換する作業を自動的におこなわせる方法について述べます。 この節を読むと、troff のデータを印字するには `lpr -t`, または、TeX DVI を印字するには `lpr -d`、 ラスタイメージデータを印字するには `lpr -v`、 などといったようにユーザが入力することができるように プリンタの設定をおこなうことができます。 この節もお読みになることをお薦めします。
* 「<<printing-advanced-of,出力フィルタ>>」 では、あまり使われない LPD の機能のすべて、すなわち、 出力フィルタに関することが記述されています。ヘッダページ (「<<printing-advanced-header-pages, ヘッダページ>>」参照) を印字させていない場合は、 多分、この節は飛ばしても構わないでしょう。
* 「<<printing-advanced-lpf,テキストフィルタ lpf>>」では、`lpf` についての説明が、ほぼ完全におこなわれています。これは FreeBSD に付属するラ インプリンタ (または、 ラインプリンタのように動作するレーザプリンタ) のための、 単純なテキストフィルタです。 プレインテキストを印字したことに対して課金をおこなう方法が 至急必要な場合、もしくは、バックスペース文字を印字しようと すると煙を発するプリンタを持っている場合は、絶対に `lpf` を検討するべきです。

[NOTE]
====
以下で述べられているさまざまなスクリプトは、[.filename]#/usr/shared/examples/printing# ディレクトリにあります。
====

[[printing-advanced-filters]]
==== フィルタはどのように機能しているか

既に言及したように、フィルタとは、プリンタにデータを送る際に、 デバイスに依存した部分を取り扱うために LPD によって起動される実行プログラムです。

LPD がジョブ中のファイルを印字しようとするとき、 LPD はフィルタプログラムを起動します。このとき、 フィルタの標準入力を印字するファイルに、 標準出力をプリンタに、そして、標準エラー出力を エラーログファイル ([.filename]#/etc/printcap# 内の `lf` 項目で指定されたファイル、または、 指定されていない場合は、デフォルトとして [.filename]#/dev/console#) にセットします。

LPD が起動するフィルタと、その引数が何であるかは、 [.filename]#/etc/printcap# ファイルの内容と、ジョブの起動時にユーザが指定した man:lpr[1] コマンドの引数に依存しています。 たとえば、ユーザが `lpr -t` と入力した場合は、 LPD は出力先のプリンタ用の `tf` 項目で指定されている troff 用のフィルタを起動させるでしょう。 ユーザがプレインテキストの印字を指示したときは、 `if` で指定されたフィルタが起動されるでしょう (このことはほとんどの場合にあてはまります。 詳細については、「<<printing-advanced-of, 出力フィルタ>>」をご覧ください)。

[.filename]#/etc/printcap# で指定可能なフィルタは次の3種類があります。

* _テキストフィルタ_ (LPD のドキュメントでは紛らわしいことに __入力フィルタ__と呼んでいますが) は一般のテキストの印字を扱います。これはデフォルトのフィルタと 考えてください。LPD では、すべてのプリンタに対して、 デフォルトでプレインテキストが印字できることを期待しています。 さらに、バックスペースやタブを正しく扱い、また、 他の特殊な文字が入力されてもプリンタに混乱を来さないように するのはテキストフィルタの仕事であると考えています。 プリンタの使用に対して課金をしなくてはならない環境にあ るときは、テキストフィルタが印字したページ数を数える作 業もしなくてはなりません。この作業は、通常、印字した行 数を数え、これをプリンタが 1 ページ当たりに印字できる行 数と比較することでおこなわれます。 テキストフィルタは、次のような引数を付けて起動されます。
+
`filter-name [ -c ] -w __width__ -l __length__ -i __indent__ -n __login__ -h __host__ __acct-file__`
+ 
ここで、
+
`-c`:::
`lpr -l` によってジョブが入力されたときに与えられます。

_width_:::
[.filename]#/etc/printcap# で指定された `pw` (page width) 項目の値が与えられます。デフォルトは、 132 です。

_length_:::
`pl` (page length) 項目で指定された値が与えられます。 デフォルトは 66 です。

_indent_:::
`lpr -i` によって与えられた字下げの量で、 デフォルトは 0 です。

_login_:::
ファイルを印字したユーザのアカウント名が 与えられます。

_host_:::
ジョブが入力されたホスト名が 与えられます。

_acct-file_:::
`af` 項目で指定されている課金データファイル の名前が与えられます。

* __変換フィルタ__は、 特定のファイル形式をプリンタ が紙に印字できるようなものに変換します。たとえば、 プリンタで ditroff 組版データを直接印字することはできません。 しかし、ditroff データをプリンタが消化し、 印字することができる形式へ変換するために、ditroff ファイル用フィルタをインストールすることができます。 「<<printing-advanced-convfilters, 変換フィルタ>>」 で、これらに関するすべてについて説明します。 プリンタの課金をする必要がある場合は、 変換フィルタでも印字ページを数える作業が必要となります。 変換フィルタは次の引数をとって起動されます。
+
`filter-name -x __pixel-width__ -y __pixel-height__ -n __login__ -h __host__ __acct-file__`
+ 
ここで、_pixel-width_ は、 `px` 項目で指定された値 (デフォルトは 0)、 _pixel-height_ は、 `py` 項目で指定された値 (デフォルトは 0) です。
* __出力フィルタ__は、 テキストフィルタが指定されて おらず、かつ、 ヘッダページの出力が許可されている場合にのみ使われます。 「<<printing-advanced-of, 出力フィルタ>>」で、これらのことについて説明します。 出力フィルタに対する引数は次の 2 つだけです。
+
`filter-name -w __width__ -l __length__`
+ 
ここで、`-w` と `-l` は、 テキストフィルタの場合と同じです。

フィルタは、次に示す終了状態をもってプログラムを _exit_ するべきです。

exit 0::
フィルタがファイルを正常に印字した場合。

exit 1::
フィルタはファイルの印字に失敗したが、 LPD に再度ファイルの印字を試みて欲しい場合。 この終了状態で終了した場合、LPD はフィルタを再スタートします。

exit 2::
フィルタはファイルの印字に失敗し、かつ、LPD に再出力を試みて欲しくない場合。この場合、LPD はそのファイルを放棄します。

FreeBSD に付属するテキストフィルタ [.filename]#/usr/libexec/lpr/lpf# は、FORM FEED 文字が送られたときやプリンタ使用に対する課金をどのようにするかを決定するために、 ページ幅やページ長の引数を利用します。また、 課金用のエントリを作成するため、ログイン名、ホスト名、 課金ファイル名の引数を利用します。

もし、フィルタの購入を検討しているならば、LPD と互換性があるかどうかを確認してください。もしそうならば、 上述の引数リストをサポートしていなければなりません。 一般向けの使用のためにフィルタを作成する計画をしている場合は、 同じ引数リストと終了コードをサポートしてください。

[[printing-advanced-if-conversion]]
==== プレインテキストのジョブを PostScript(R) プリンタで印字する

コンピュータと PostScript(R) (または、他の言語に対応した) プリンタをあなたしか使用しない場合は、プリンタにプレ インテキストを絶対に送らない、そして、 プリンタにプレインテキストを送りたがっている 様々なプログラムの機能を決して使わないことにしてください。そうすれば、 この節に書かれたことに心を煩わせる必要はまったくなくなります。

しかし、PostScript(R) とプレインテキストの両方のジョブをプリンタへ送りたいと思っている場合は、 プリンタ設定についての要求が増えるでしょう。 両者をプリンタへ送信するためには、 到着したジョブがプレインテキストであるか PostScript(R) であるかを検出するテキストフィルタが必要です。 PostScript(R) のジョブはすべて `%!` で始まらなければならないことになっています (他のプリンタ言語に関しては、 プリンタのドキュメントをご覧ください)。 ジョブの最初の 2 文字がこれならば、PostScript(R) であることが分かります。 したがって、 ジョブのそれ以降の部分をプリンタに直接送ることができます (訳注: PostScript(R) では、_%_ 以降はコメントとして扱われるので、最初の _%!_ の行を読み捨てても問題はない)。 最初の2文字が _%!_ でない場合は、 フィルタはテキストを PostScript(R) に変換し、 その結果を使って印字をおこないます。

この作業をどうやってやればよいのでしょうか。

シリアルポートにプリンタを接続した場合は、 `lprps` をインストールすることをお勧めします。 `lprps` は PostScript(R) 用のフィルタで、 プリンタとの双方向通信をおこないます。 このフィルタでは、プリンタからの冗長な情報を得ることで、 プリンタの状況を示すファイルが更新されていきます。 したがって、ユーザや管理者は (``トナー残量少``や ``紙詰まり``といった) プリンタの状況を正確に知ることができます。しかし、 もっと重要なことは、`psif` と呼ばれるプログラムが含まれているということです。 このプログラムは、 入力されたジョブがプレインテキストかどうかを検出し、 これを PostScript(R) に変換するために、`textps` (`lprps` に付属する別のプログラム) を呼び出します。そして、このジョブをプリンタに送るために、 `lprps` が使われます。

`lprps` は FreeBSD Ports Collection に含まれています (crossref:ports[ports,Ports Collection] を参照してください)。 紙のサイズに合わせて package:print/lprps-a4[] または package:print/lprps-letter[] port をインストールしてください。`lprps` をインストールした後は、`lprps` の一部である `psif` プログラムのパス名を指定するだけです。Ports Collection から `lprps` をインストールしたときは、 [.filename]#/etc/printcap# の中のシリアル接続した PostScript(R) プリンタのエントリに対して、次を使ってください。 

[.programlisting]
....
:if=/usr/local/libexec/psif:
....

LPD にプリンタをリード・ライトモードでオープンさせるために、 `rw` 項目も指定すべきです。

パラレルポート接続の PostScript(R) プリンタの場合 (すなわち、 `lprps` が 必要としているプリンタとの双方向通信ができない)、 テキストフィルタとして次のシェルスクリプトを使うことができます。

[.programlisting]
....
#!/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
#

IFS="" read -r 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(R) へ変換するために別にインストールしたプログラムです。 テキストから PostScript(R) へ変換するのには、 お好みのどんなプログラムでも使うことができます。FreeBSD Ports Collection (crossref:ports[ports,Ports Collection] を参照してください) には、`a2ps` と呼ばれるテキストから PostScript(R) に変換するプログラムが入っています。

[[printing-advanced-ps]]
==== 非 PostScript(R) プリンタによる PostScript(R) のシミュレート

PostScript(R) は質の高い組版と印字をおこなうための __事実上の__標準です。しかしながら、PostScript(R) は、__高価な__標準です。ありがたいことに、 Aladdin Enterprises から Ghostscript と呼ばれる、 PostScript(R) 互換の動作をするフリーのプログラムが出されていて、 FreeBSD で動きます。 Ghostscript はほとんどの PostScript(R) ファイルを読むことができ、 これらの各ページを多くのブランドの非 PostScript(R) プリンタを含む 様々なデバイス用に変換することができます。 Ghostscript をインストールし、 プリンタ用の特別なテキストフィルタを使うことによって、 非 PostScript(R) プリンタをあたかも本物の PostScript(R) プリンタであるかのように動作させることができます。

Ghostscript は FreeBSD Ports Collection に入っています。 複数のバージョンがありますが、最も良く使われているバージョンは package:print/ghostscript-gpl[] です。

PostScript(R) プリンタをシミュレートさせる場合は、 テキストフィルタに PostScript(R) ファイルを印字しようとしているかどうかを検出させます。 PostScript(R) ファイルでない場合は、 フィルタはそのファイルを直接プリンタに送ります (訳注: テキストファイルを直接印字できない場合は、もちろん、 変換フィルタを通す必要があります)。PostScript(R) の場合は、 まず、Ghostscript を使い、 ファイルをそのプリンタが理解できる形式へ変換します。

次の例のスクリプトは、Hewlett Packard DeskJet 500 プリンタ用 のテキストフィルタです。 他のプリンタで用いるときは、`-sDEVICE` 引数を `gs` (Ghostscript) コマンドに変えてください (`gs -h` と入力すると、現在インストールされている Ghostscript でサポートされているデバイスのリストが得られます)。

[.programlisting]
....
#!/bin/sh
#
#  ifhp - Print Ghostscript-simulated PostScript on a DeskJet 500
#  Installed in /usr/local/libexec/ifhp

#
#  Treat LF as CR+LF (to avoid the "staircase effect" on HP/PCL
#  printers):
#
printf "\033&k2G" || exit 2

#
#  Read first two characters of the file
#
IFS="" read -r first_line
first_two_chars=`expr "$first_line" : '\(..\)'`

if [ "$first_two_chars" = "%!" ]; then
    #
    #  It is PostScript; use Ghostscript to scan-convert and print it.
    #
    /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 feed
    #  at the end to eject the last page.
    #
    echo "$first_line" && cat && printf "\033&l0H" &&
    exit 0
fi

exit 2
....

最後に、`if` 項目を通して、LPD にこのフィルタを教えてやる必要があります。

[.programlisting]
....
:if=/usr/local/libexec/ifhp:
....

これでおしまいです。`lpr plain.text` とか `lpr whatever.ps` と入力してみましょう。どちらも正常に印字されるはずです。

[NOTE]
====
日本語を印字する場合は、 日本語対応の Ghostscript が必要です。日本語対応版の Ghostscript も Ports Collection に入っています。
====

[[printing-advanced-convfilters]]
==== 変換フィルタ

「<<printing-simple,プリンタ設定導入編>>」 に書かれた簡単な設定が完了したら、最初に、 やってみたいと思うことは、多分 (プレイン ASCII テキストに加えて) 好みのファイル形式のための変換フィルタをインストールすることでしょう。 

===== なぜ、変換フィルタをインストールするのか?

変換フィルタによって、 様々な種類のファイルを印字することが簡単になります。たとえば、TeX 組版システムでたくさんの仕事をしたと仮定しましょう。 そして、PostScript(R) プリンタが接続 されているとします。 すると、TeX で DVI ファイルを作成する度に、DVI ファイルを印字するために、 これを PostScript(R) ファイルに変換する必要があります。 このコマンドは次のようになるでしょう。

[source,shell]
....
% dvips seaweed-analysis.dvi
% lpr seaweed-analysis.ps
....

DVI ファイル用の変換フィルタがインストールしてあると、 LPD に変換を肩代わりさせることで毎回毎回 おこなわなければならなかった面倒な変換作業を省くことができます。 つまり、DVI を生成したら、 次のようなコマンドを入力するだけで、これが印字されます。 

[source,shell]
....
% lpr -d seaweed-analysis.dvi
....

LPD に DVI ファイルの変換をさせるためには、 `-d` オプション を指定します。 変換オプションのリストは「<<printing-lpr-options-format, 整形と変換に関するオプション>>」 に載せてあります。

変化のオプションのそれぞれをプリンタに サポートさせるためには、 __変換フィルタ__をインストールし、 そのパス名を [.filename]#/etc/printcap# の中で指定しなくてはなりません。変換フィルタは、 プレインテキストを印字する代わりに、フィルタはファイルを プリンタが理解できる形式に変換するところを除けば、 「プリンタの簡単な設定」で説明したテキストファイル (「<<printing-textfilter, テキストフィルタのインストール>>」 を見て下さい) に似ています。

===== どの変換フィルタをインストールすべきか?

使いたいと思う変換フィルタをインストールすべきです。 DVI のデータを頻繁に印字するならば、DVI 変換フィルタ をインストールするのが適切でしょう。印字しなくてはなら ない troff を大量に抱えている場合は、多分、 troff フィルタが欲しくなるはずです。

次の表は、LPD で動作するフィルタと、 [.filename]#/etc/printcap# ファイルでのエントリする項目、そして、 `lpr` コマンドで呼び出す方法をまとめたものです。

[.informaltable]
[cols="1,1,1", frame="none", options="header"]
|===
| ファイル形式
| /etc/printcap項目
| lpr オプション

|cifplot
|`cf`
|`-c`

|DVI
|`df`
|`-d`

|plot
|`gf`
|`-g`

|ditroff
|`nf`
|`-n`

|FORTRAN text
|`rf`
|`-f`

|troff
|`tf`
|`-f`

|raster
|`vf`
|`-v`

|プレインテキスト
|`if`
|なし、`-p`、または `-l`
|===

先の例のように、`lpr -d` を使うためには、出力先のプリンタの [.filename]#/etc/printcap# 内のエントリで、 `df` 項目が必要であることが分かります。

反論はあるかも知れませんが、FORTRAN テキストや plot のような形式は、多分、廃れてていくでしょう。 あなたのサイトで、自前のフィルタをインストールするだけで、 プリントオプションのいくつか、あるいは、 全部に新しい意味を与えることができます。たとえば、 Printerleaf ファイル (Interleaf デスクトップパブリッシングプログラムによるファイル) を直接印字したいとします。 そして、Printerleaf 用の変換フィルタを `gf` 項目で 指定したパスにインストールすれば、`lpr -g` の意味は "Printerleaf ファイルを印字する" 意味だとユーザに教えることができます。 

===== 変換フィルタのインストール

変換フィルタは FreeBSD の基本システムのインストールとは別にインストールするプログラムなので、 変換フィルタは、 [.filename]#/usr/local# ディレクトリの下に置くべきでしょう。 フィルタは LPD だけが実行する特別なプログラム、 すなわち、一般ユーザが実行する必要すらないプログラムなので、 [.filename]#/usr/local/libexec# ディレクトリに置くのが普通です。

変換フィルタを使用可能にするためには、 [.filename]#/etc/printcap# の目的のプリンタの適切な項目に フィルタがあるパス名を指定します。

DVI 変換フィルタをプリンタ `bamboo` のエントリに加えてみましょう。プリンタ `bamboo` の `df` 項目を新たに加えた [.filename]#/etc/printcap# ファイルの例を以下に再掲します。

[.programlisting]
....
#
#  /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/ttyu5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:
....

DVI フィルタは [.filename]#/usr/local/libexec/psdf# という 名前のシェルスクリプトです。 このスクリプトは次のようになっています。

[.programlisting]
....
#!/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`) で、 標準入力上で起動しています。標準入力は印字するジョブです。 それから、PostScript(R) プリンタ用フィルタ `lprps` (これについては「<<printing-advanced-if-conversion, プレインテキストのジョブを PostScript(R) プリンタで印字する>>」 を参照してください) を LPD に与えられた引数を付けて起動します。 `lprps` はこれらの引数を印字されたページ分の課金をおこなうために使われます。 

===== 変換フィルタのその他の例

変換フィルタのインストールには決まったステップがないので、 この節では、例をもっと挙げることにします。 これを自分でフィルタを作る際のガイドにしてください。 適当な例があったら、それをそのまま使ってください。

次のスクリプト例は、Hewlett Packard LaserJet III-Si のための、raster (ええと・・実は、GIF ファイル) 用の変換フィルタです。

[.programlisting]
....
#!/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 ファイルから PNM (portable anymap) 形式に変換し、次に PGM (portable graymap) 形式に変換してから、 LaserJet/PCL-互換データに変換しています。

上記のフィルタを使うプリンタのためのエントリを付け加えた [.filename]#/etc/printcap# ファイルは次のようになります。

[.programlisting]
....
#
#  /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:
....

次のスクリプトは、PostScript(R) プリンタ `bamboo` のための groff 組版システムの troff データのための変換フィルタです。

[.programlisting]
....
#!/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` をまた利用しています。 プリンタがパラレルポートに接続されている場合は、代わりに、 次のスクリプトを使うかもしれません。

[.programlisting]
....
#!/bin/sh
#
#  pstf - Convert groff's troff data into PS, then print.
#  Installed in /usr/local/libexec/pstf
#
exec grops
....

これで完成しました。次に、フィルタを使用可能にするため に [.filename]#/etc/printcap# に加える必要があるエントリを示します。

[.programlisting]
....
:tf=/usr/local/libexec/pstf:
....

次の例をみたら、FORTRAN のベテランは赤面するかもしれません。 この FORTRAN テキストフィルタは、 プレインテキストを直接印字できるすべてのプリンタで利用できます。 このフィルタをプリンタ `teak` にインストールすることにしましょう。

[.programlisting]
....
#!/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
....

そして、このフィルタを使用可能にするため、以下の行を [.filename]#/etc/printcap# のプリンタ `teak` のエントリに加えます。

[.programlisting]
....
:rf=/usr/local/libexec/hprf:
....

これが最後の、そして、若干複雑な例です。前に紹介した LaserJet プリンタ `teak` に、DVI フィルタを加える ことにしましょう。最初に、 簡単な部分をおこないます。すなわち、DVI フィルタの位置を [.filename]#/etc/printcap# に書き加えます。 

[.programlisting]
....
:df=/usr/local/libexec/hpdf:
....

さて、難しい部分であるフィルタの作成をおこないます。 このために、DVI から LaserJet/PCL への変換プログラムが必要です。FreeBSD の Ports Collection (crossref:ports[ports,Ports Collection] を参照してください) には、それがあります。 package:dvi2xx[] というのがその port の名前です。 これをインストールすると、必要なプログラム `dvilj2p` が使えます。このプログラムは DVI を LaserJet IIp、LaserJet III、そして LaserJet 2000 の互換コードへ変換してくれます。

`dvilj2p` はフィルタ `hpdf` を極めて複雑にしています。 なぜなら、`dvilj2p` は標準入力からデータを読み込むことができないからです。 このプログラムを働かせるためには、ファイル名が必要です。 もっと悪いことに、ファイル名は [.filename]##.dvi## で終わっている必要があり、標準入力の代わりに、 [.filename]##/dev/fd/0## を使うのは問題があります。 この問題は、([.filename]##.dvi## で終わる) 一時的なファイル名から[.filename]##/dev/fd/0## に (シンボリックな) リンクを張る ことで回避することができます。これで、 `dvilj2p` に強制的に標準入力からデータを読み込ませることができます。

もう1つの問題は、一時的なリンクを張るために [.filename]#/tmp# ディレクトリを使うことができないという事実です。 シンボリックリンクはユーザ、グループが `bin` であるユーザに所有されています。フィルタはユーザ `daemon` として起動します。そして、 [.filename]#/tmp# ディレクトリはスティッキービットが立っています。 フィルタはリンクを作ることができます。しかし、 リンクは別のユーザに所有されているため、 作業が終了したとき、このリンクを削除することができません。

その代わりに、シンボリックリンクは現在の作業ディレクトリ、 すなわち、スプーリングディレクトリ ([.filename]#/etc/printcap# の `sd` 項目で指定する) に作ることにします。 フィルタが作業するにはここの場所は完璧な場所で、なぜなら、 特に、スプーリングディレクトリのディ スクの空き容量は (ときどき) [.filename]#/tmp# ディレクトリよりもたくさんあるからです。

以下に示すのが最後のフィルタです。

[.programlisting]
....
#!/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
....

[[printing-advanced-autoconv]]
===== 自動変換: その他の変換フィルタ

ここまでに述べてきたフィルタによって、 印字環境の能率が上がったことと思います。しかし、 これはどのフィルタを使うかを (man:lpr[1] のコマンドライン上で) ユーザが指定しなくてはならないという代価を支払って実現されています。 コンピュータの事情にあまり詳しくないユーザにとって、 フィルタのオプションを指定させられるということは いらいらさせられるものになるでしょう。更に悪いことに、 間違ったフィルタオプションを指定されると、 間違った形式のファイルがそのフィルタに適用されることになり、 その結果、何百枚もの紙を吐き出すことになるかもしれません。

そのような結果になるならば、 変換フィルタをインストールするよりもむしろ、 テキストフィルタ (これがデフォルトフィルタなので) に印字するよう要求されたファイルの形式を検出させ、自動的に、 適切な変換フィルタを起動するようにしたいと思うかもしれません。 ここでは `file` コマンドのようなツールを役立たせることができます。 もちろん、_いくつかの_ ファイル形式の違いを見分けることは難しいことでしょう。 そして、もちろん、それらのファイルに対しては、 変換フィルタを提供するだけで済ますこともできるのです。

FreeBSD Ports Collection には、`apsfilter` (package:print/apsfilter[]) と呼ばれる自動変換をおこなうテキストフィルタがあります。 このフィルタは プレインテキスト、PostScript(R), DVI など、ほとんどすべてのファイル形式を検出し、適当な変換をおこなった後、 データを印字することができます。

[[printing-advanced-of]]
==== 出力フィルタ

LPD スプーリングシステムでは、 ここまでにまだ取り上げていないフィルタ形式、 出力フィルタをサポートしています。出力フィルタは、 テキストフィルタのように、 プレインテキストのみを印字するために意図されたものですが、 非常に簡単化されています。テキストフィルタを用いずに、 出力フィルタを使っている場合は、次のようになります。

* LPD はジョブ中の各ファイルに一度ではなく、 ジョブ全体に対して一度だけ出力フィルタを起動します。
* LPD は出力フィルタに対し、 ジョブ中のファイルの先頭や末尾を特定するための対策を 一切おこなっていません。
* LPD はユーザのログイン名やホスト名をフィルタに渡しません。 したがって、課金の処理をおこなうことは考えていません。 実際、出力フィルタには、以下2つの引数しか与えられません。
+
`filter-name -w__width__ -l__length__`
+ 
ここで、_width_ は対象となるプリンタの `pw` 項目、 _length_ は `pl` 項目に指定された数です。

出力フィルタの簡便さに誘惑されてはいけません。もし、 ジョブ中のそれぞれのファイルに別のページ番号を付加しようとしても、 出力フィルタは__うまく動作しないでしょう__。 そのような動作を期待しているならば、 (入力フィルタとしても知られている) テキストフィルタを使ってください。 詳しくは、「<<printing-textfilter, テキストフィルタのインストール>>」をご覧ください。 さらに、出力フィルタは、実のところ、 __もっと複雑__になっています。まず、 特殊なフラグ文字を検出するために、 フィルタに送られてくるバイトストリームを検査する必要があります。 また、LPD に代わって、 自分自身にシグナルを送らなければなりません。

しかしながら、ヘッダページの印字をおこないたくて、 エスケープシーケンスやヘッダページを印字できるようにするその他の初期化文字列を送信する必要がある場合は、 出力ファイルが__必要__です。 (しかし、 ヘッダページを要求したユーザに対して課金しようとするのもまた無駄なことです。 LPD は出力フィルタにユーザやホストの情報を渡しません)。

1 台のプリンタに対し、LPD では出力フィルタとテキストやその他のフィルタを両方使うことができます。 このような場合、LPD はヘッダページ (「<<printing-advanced-header-pages, ヘッダページ>>」 を参照してください) だけを印字させるために、出力フィルタを起動させます。 それから LPD では、出力フィルタに 2 バイトの文字 (ASCII 031 の次に ASCII 001) を送ることで、 出力フィルタが__自分自身を停止する__ことを期待しています。 2 バイト (031, 001) が出力フィルタに送られたとき、 出力フィルタは自分自身にシグナル `SIGSTOP` を送ることによって停止するはずです。 LPD がその他のフィルタを動かし終わると、 出力フィルタにシグナル `SIGCONT` を送って、出力フィルタを再起動します。

出力フィルタがあり、 テキストフィルタが__ない__場合、 LPD はプレインテキストジョブを扱う場合に、 出力フィルタを使います。前述したように、出力フィルタでは、 ジョブ中の各ファイルの間に FORM FEED 文字や紙を送る他の文字を入れることはしません。 この動作は多分、 あなたが求めているものとは__異なっている__でしょう。 ほとんどの場合において、テキストフィルタが必要なはずです。

プログラム `lpf` は、 テキストフィルタの項で既に紹介しましたが、 出力フィルタとしても動作させることができます。もし、 簡便で極悪な出力フィルタが必要で、かつ、 バイトストリームを検査したりシグナルを送るコードを書きたくないときには、 `lpf` をお試しください。 あるいは、プリントが要求する初期化コードを送るために、 `lpf` をシェルスクリプトに包んで使うこともできます。

[[printing-advanced-lpf]]
==== テキストフィルタ `lpf`

プログラム [.filename]#/usr/libexec/lpr/lpf# は、 FreeBSD の バイナリ配布に付属しているテキストフィルタ (入力フィルタ) で、出力を字下げしたり (`lpr -i` でジョブが入力さ れたとき)、 文字を未処理のままプリンタに送ったり (`lpr -l` でジョブが入力されたとき)、 ジョブ中のバックスペースやタブの印字位置を調節したり、 印字したページに対して課金したりすることができます。また、 このフィルタは出力フィルタとしても動作させることができます。

`lpf` フィルタは多くの印字環境において使用することに適しています。 このフィルタには、プリンタに初期化文字列を送る機能はありませんが、 必要とされる初期化をおこない、それから `lpf` を実行させるためのシェルスクリプトを作成するのはたやすいことです。 

`lpf` に対して、 印字ページへの課金を正確におこなわせるためには、 [.filename]#/etc/printcap# ファイルの中の `pw` と `pl` の項目に正確な値を入れておく必要があります。これらの値は、 どのくらいの量のテキストがページにフィットするか、また、 ユーザのジョブが何ページあるのかを調べるために使われます。 プリンタの課金についての詳しい情報については、「<<printing-advanced-acct, プリンタの利用に対する課金>>」をご覧ください。

[[printing-advanced-header-pages]]
=== ヘッダページ

あなたが管理するシステムのユーザが __たくさん__おり、 ユーザ全員が様々なプリンタを使用する場合、多分、 必要悪である__ヘッダページ__を 印字させることを検討したいと思うかもしれません。

ヘッダページは、_バナー_ とか _バーストページ_ としても知られていますが、 出力されたジョブが誰によるものなのかを特定させる働きがあります。 印字結果の山の中において、 ユーザのジョブによって印字された本物のドキュメント部分よりも際立たせるために、 ヘッダページは、通常、多分、縁が装飾されている大きな太文字で印字されます。 ヘッダページにより、 ユーザは自分が出したジョブがどこにあるのかをすばやく見つけることができます。 ヘッダページの欠点は、明らかに、すべてのジョブに対して、 紙が 1 枚余分に印字されるということです。 この紙の有効期間は短く、2 ～ 3 分も続きません。最終的に、 これらの紙は再利用紙入れの中かくずの山に入れられることでしょう (ヘッダページはジョブ中の各ファイル毎に印字されるのではなく、 ジョブ毎に印字されるということに注意してください。したがって、 紙の消費はそれほどひどくはないかもしれません)。

_もし_、 プリンタがプレインテキストを直接印字できるならば、LPD システムは印字物に対して自動的にヘッダページを付けることができます。 PostScript(R) プリンタを使っている場合は、 ヘッダページを生成する外部プログラムが必要になります。これについては、 「<<printing-advanced-header-pages-ps,PostScript(R) プリンタでのヘッダページ>>」をご覧ください。

[[printing-advanced-header-pages-enabling]]
==== ヘッダページの印字を許可する

「<<printing-simple,プリンタ設定導入編 >>」節では、[.filename]#/etc/printcap# ファイルの `sh` (''suppress header'' : "ヘッダを供給しない" という意味) を指定して、 ヘッダページの印字を止めていました。 プリンタでのヘッダページの印字を許可するには、 `sh` 項目を取り除くだけでよいのです。

とても簡単そうに見えるけど、本当かな?

それは本当です。 プリンタに初期化文字列を送るための 出力フィルタを用意しなくてはならないかもしれません。次に、Hewlett Packard PCL 互換プリンタの例を挙げます。

[.programlisting]
....
#!/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` 項目に出力フィルタのパス名を指定してください。 詳細については、「<<printing-advanced-of,出力フィルタ>>」節 をご覧ください。

次に、以前紹介したプリンタ `teak` のための [.filename]#/etc/printcap# ファイルの例を示します。ここでは、 ヘッダページの印字を許可し、上記の出力フィルタを追加しました。 

[.programlisting]
....
#
#  /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` からジョブを印字させたとき、 それぞれのジョブ毎にヘッダページが印字されます。 もし、ユーザが印字物を探すのに時間を費やしたいと思うなら、 `lpr -h` によってジョブを入力することで、 ヘッダページの印字を止めることができます。 これ以外の man:lpr[1] のオプションについては、 「<<printing-lpr-options-misc, ヘッダページ用オプション>>」節をご覧ください。

[NOTE]
====
LPD では、ヘッダページの最後に、 FORM FEED 文字が印字されます。 プリンタに紙排出をさせるために、別な文字、 もしくは、別な文字列が利用されている場合は、 [.filename]#/etc/printcap# 中の `ff` 項目で指定することができます。
====

[[printing-advanced-header-pages-controlling]]
==== ヘッダページを制御する

ヘッダページの印字が許可されていると、LPD は __長いヘッダ__を作ります。これには、 紙全面に大きな文字でユーザ名、ホスト名、 ジョブ名が書かれています。次に、このヘッダページの例を示 します (`kelly` がジョブ名 "outline" を `rose` というホストから印字 された場合)。

[source,shell]
....
      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 はこのテキストの終わりに FORM FEED 文字を加えます ので、ジョブは新しいページから開始されます (ただし、 [.filename]#/etc/printcap# で出力先のプリンタのエントリに `sf` (suppress form feeds) が指定されているときはこ の限りではありません)。

お望みならば、LPD に__短いヘッダページ__を出力させることもできます。 この場合は、 [.filename]#/etc/printcap# ファイルの中で `sb` (short banner) を指定してください。 ヘッダページは次のようになります。

[source,shell]
....
rose:kelly  Job: outline  Date: Sun Sep 17 11:07:51 1995
....

デフォルトでは、LPD はヘッダページを最初に印字し、次にジョブの印字をおこないます。 この順番を逆にするときは、 [.filename]#/etc/printcap# で `hl` (header last) を指定してください。

[[printing-advanced-header-pages-accounting]]
==== ヘッダページに対する課金

LPD に備わっているヘッダページ出力機能を使うと、 入力されたジョブに対して課金をおこなうことができても、 ヘッダページは__無料__で提供しなくてはならない、 という特有のやり方を強要されます。

なぜでしょうか。

出力フィルタは単なる外部プログラムなので、 課金をするための制御をおこなうとすれば、 それはヘッダページを印字するときですが、出力フィルタには、 _ユーザ名とホスト名_ の情報や課金情報を格納するファイルがどれな のかということが知らされません。それゆえ、出力ファイルには、 誰にプリンタ利用の課金をおこなえばよいのかが分からないのです。 テキストフィルタやその他の変換フィルタ (これらのフィルタはユーザやホストの情報が知らされます) が出力ページの枚数に "1 ページ分水増しする" だけでは十分ではありません。 なぜなら、ユーザは `lpr -h` に よってヘッダページの出力を止めることができるからです。 やみくもに 1 ページを水増しすると、 印字されてもいないヘッダページに対する 料金をとることになります。基本的に、`lpr -h` は環境に優しい心を持つユーザに好まれるオプションですが、 これを使うように奨励することもできません。

各々のフィルタに独自のヘッダページを生成させる (その結果、ヘッダページに課金することができる) という方法__でも十分であるとはいえません__。 この場合、LPD はフィルタに `-h` の情報を送りませんので、`lpr -h` によってヘッダページを印字しないオプションを選択したとしても、 依然としてヘッダページは印字され、 その分の課金がおこなわれてしまいます。

では、どのような選択肢があるのでしょうか。

ヘッダページへの課金に関しては、 次のことができます。

* LPD のやり方を受け入れ、 ヘッダページは無料とする。
* LPRng などの LPD の代替品をインストールする。 LPD と入れ替えが可能な他のスプーリングソフトウェアに関しては、 <<printing-lpd-alternatives,標準スプーラの代替品>> をご覧ください。
* _スマートな_ 出力フィルタを作成する。通常、 出力フィルタはプリンタを初期化するか、 単純な文字列変換をする程度の働きしかしません。 (テキスト (入力) フィルタがない場合) 出力フィルタはヘッダページとプレインテキストの印字をおこなうのに適しています。 プレインテキストを印字するためのテキストフィルタがない場合、 LPD はヘッダページを印字するためだけの目的で出力フィルタを起動します。 そして、LPD が生成するヘッダページのテキストを解析することにより、 出力フィルタはヘッダページに課金するために必要なユーザ名と ホスト名を取得することができます。この方式の唯一の問題点は、 出力フィルタは課金情報を格納するデータファイルの名前を知ることが できないということです (`af` 項目で指定されたファイル名は 出力ファイルに渡されません)。しかし、既知の 名前の課金データファイルを使うのならば、 その名前を出力フィルタのプログラム中に埋め込むことができます。 解析の手順を簡単にするためには、 [.filename]#/etc/printcap# で `sh` 項目 (短いヘッダを指定) を使うとよいでしょう。 そしてまた、 ここまでの方法は少なからぬトラブルを生じさせるかもしれません。 そうなれば、もちろんユーザはヘッダページを無料で 提供してくれる気前のよいシステム管理者に感謝することでしょう。 

[[printing-advanced-header-pages-ps]]
==== PostScript(R) プリンタでのヘッダページ

これまでに述べたように、LPD ではプレインテキストのヘッダページをたくさんのプリンタに合うように生成することができます。 残念ながら、PostScript(R) プリンタは、 プレインテキストを直接印字することができません。ですから、 LPD のヘッダページ機能はまったく、 あるいはほとんどの場合、役に立ちません。

ヘッダページを出力するための自明な方法の1つに、 すべての変換フィルタとテキストフィルタにヘッダページを生成させる方法があります。 フィルタは、 適切なヘッダページを生成するために、 ユーザ名とホスト名の引数を使うべきです。この方法の欠点は、いつでも、 `lpr -h` によってジョブが入力された場合でさえも、 ヘッダページが印字されるということです。

この方法で試してみましょう。次のスクリプトは、3 つの引数 (ユーザ のログイン名、ホスト名、ジョブ名) をとり、簡単な PostScript(R) 用 のヘッダページを生成します。

[.programlisting]
....
#!/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
....

そして、変換フィルタやテキストフィルタがそれぞれ、 最初にこのスクリプトを起動することで、 ヘッダページが出力され、それから、 ユーザのジョブの印字をおこないます。次に、 このドキュメントの始めのほうで紹介した DVI 変換フィルタを、 ヘッダページを印字するように変更したものを示します。

[.programlisting]
....
#!/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
....

このフィルタがユーザ名やホスト名を決定するために 引数リストをどのように解析しなくてはならないかという点に注意してください。 この解析方法は他の変換フィルタに対しても同様です。 しかしながら、テキストフィルタについては、 引数の設定が少し異なっています (これについては、「<<printing-advanced-filters, フィルタはどのように機能しているか>>」 をご覧ください)。

前述の通り、上記の手法は、極めて単純なのにも関らず、 `lpr` で "ヘッダページを印字しない" オプション (`-h` オプション) が使えなくなっています。 ユーザが森林資源を (あるいは、 ヘッダページが課金されているならば、その僅かな金額を)、 節約したいと望んでいる場合でも、 すべてのフィルタがすべてのジョブ毎にヘッダページを印字 することになっているので、節約することはできません。

ジョブ毎に印字されるヘッダページを ユーザが抑制できるようにするためには、「<<printing-advanced-header-pages-accounting, ヘッダページに対する課金>>」で紹介したトリックを 使う必要があります。すなわち、LPD が生成するヘッダページの解析をおこない、PostScript(R) 版のヘッダページを出力させる出力フィルタを作るのです。 この場合、ユーザが `lpr -h` でジョブを入力すると、 LPD はヘッダページを生成しなくなり、また、 出力フィルタも起動されません。そうでないならば、 作成した出力フィルタが LPD からのテキストを読み込み、ヘッダページを印字する適当な PostScript(R) のコードがプリンタに送られるでしょう。

PostScript(R) プリンタがシリアルポートに接続されている場合、 出力フィルタとして `lprps` を、 上記の動作をおこなうものとして `psof` を使うことができます。ただし、`psof` はヘッダページに対して課金をおこないませんので注意してください。 

[[printing-advanced-network-printers]]
=== リモートプリンタからの出力

FreeBSD では、ネットワーク越しの印字、すなわち、 ジョブをリモートプリンタに送ることをサポートしています。 リモートプリンタからの出力をするには、一般に、 次の 2 つを参照してください。 

* リモートホストに接続されたプリンタにアクセスする方法。 プリンタがあるホストのシリアル、 または、パラレルインタフェースに接続されている場合、 ネットワーク上の他のホストからこのプリンタにアクセスできるように LPD を設定します。「<<printing-advanced-network-rm,リモートホストに 接続されたプリンタ>>」 でどのようにするかを説明します。
* ネットワークに直接接続されているプリンタにアクセスする方法。 プリンタに、旧来のシリアル、または、 パラレルインタフェースに加えて (もしくは、これらに代わって) ネットワーク用のインタフェースがある場合。 そのようなプリンタは次のように動作するでしょう。

** そのプリンタが LPD のプロトコルを理解でき、リモートホストからのジョブを キューに入れることさえできる場合。この場合、 プリンタは、LPD が起動している一般のホストのように振る舞います。 そのようなプリンタを設定するために、 「<<printing-advanced-network-rm, リモートホストに接続されたプリンタ>>」 と同様の手順をおこなってください。
** そのプリンタが、 データストリームによるネットワーク接続をサポートしている場合。 この場合、ネットワーク上の1つのホストとしてプリンタを "接続" します。 このホストは、ジョブをスプーリングする責任を負い、 スプーリングされたジョブはプリンタに送られます。 そのようなプリンタをインストールするためのいくつかの提案が 「<<printing-advanced-network-net-if, ネットワークにおけるデータストリームの インタフェースを持つプリンタ>>」にあります。

[[printing-advanced-network-rm]]
==== リモートホストに接続されたプリンタ

LPD スプーリングシステムでは LPD (または LPD 互換のシステム) が起動している他のホストへジョブを送る機能が 始めからサポートされています。この機能により、 あるホストに接続されたプリンタへ、 他のホストからアクセスできるようになります。また、 LPD プロトコルを理解するネットワークインタフェースを持ったプリンタに対しても、 この機能は働きます。

リモートプリンタへの出力を許可するためには、最初に、 あるホスト (これを、 __プリンタホスト__と呼びます) にプリンタを接続します。そして、「<<printing-simple, プリンタ設定導入編>>」 に書かれた簡単なプリンタの設定をおこなってください。 必要ならば、「<<printing-advanced,プリンタ設定上級編>>」 にある、更に進んだ設定をおこなってください。そして、 そのプリンタをテストしてうまく動作することを確認し、LPD に許可した機能がうまく働くかどうかを見てください。さらに __ローカルホスト__が __プリンタホスト__の LPD サービスの使用を許可されているか確認して下さい (「<<printing-advanced-restricting-remote, リモートホストからの利用を制限する >>」参照)。

LPD 互換のネットワークインタフェースを持つプリンタを使用している場合は、 そのプリンタ自身が以下で説明する __プリンタホスト__になります。そして、 __プリンタ名__とは、 そのプリンタに設定した名前のことを指します。 これについては、プリンタ、および (または)、 プリンタのネットワークインタフェースに付属するドキュメントを参照してください。

[TIP]
====

ヒューレット・パッカード社の Laserjet シリーズを使用している場合には、 プリンタ名を `text` とすると、 自動的に LF から CRLF への変換が行なわれます。 そのため、[.filename]#hpif# スクリプトは必要ありません。 
====

次に、 そのプリンタにアクセスしたいと思っている他ホストにおいて、 そのホストの [.filename]#/etc/printcap# ファイルに次にあげるエントリを作ります。

. 名前のエントリ。どんな名前でもよいのですが、簡単のため、多分、 プリンタホストで設定されたプリンタ名や別名と同じものを使いたいと思うでしょう。
. `lp` 項目で指定されるデバイスは明示的に空にします (`:lp=:` とします)。
. スプーリングディレクトリを作成し、 `sd` 項目でその位置を指定します。 LPD では、プリンタホストにジョブを送信するまでの間、 このディレクトリにジョブを格納します。
. `rm` 項目でプリンタホストの名前を指定します。
. `rp` 項目で __プリンタホスト__に接続したプリンタ名を指定します。

これで終わりです。 変換フィルタやページの大きさやその他の事項を [.filename]#/etc/printcap# に加える必要はありません。

次に、 リモートホストに接続されたプリンタで印字するための設定例を示します。 ホスト `rose` には 2 台のプリンタ `bamboo` と `rattan` が接続されています。これらのプリンタをホスト `orchid` のユーザが使えるようにしましょう。最初に `orchid` の [.filename]#/etc/printcap# を示します (このファイルは、「<<printing-advanced-header-pages-enabling, ヘッダページの出力を許可する>>」 で参照することができます)。このファイルには、既に、プリンタ `teak` 用のエントリがありました。以下では、 これに、ホスト `rose` にある2台のプリンタ用のエントリが加えられています。

[.programlisting]
....
#
#  /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` で必要となる作業はスプーリングディレクトリを作ることだけです。

[source,shell]
....
# 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` のユーザが `rattan` と `bamboo` で印字することができるようになりました。 たとえば、`orchid` のユーザが次のように入力したとします。

[source,shell]
....
% lpr -P bamboo -d sushi-review.dvi
....

すると、`orchid` の LPD システムは、 ジョブをスプーリングディレクトリ [.filename]#/var/spool/lpd/bamboo# にコピーし、これが DVI ファイルを印字するジョブであることを記録します。 ホスト `rose` の `bamboo` スプーリングディレクトリに十分な容量が確保でき次第、 両者の LPD は、ジョブのファイルを `rose` に転送します。 このファイルは、そのすべてが印字されるまで、`rose` のキューに留まります。 (`bamboo` は PostScript(R) プリンタなので) DVI から PostScript(R) への変換は `rose` でおこなわれます。

[[printing-advanced-network-net-if]]
==== ネットワークにおけるデータストリームの インタフェースを持つプリンタ

プリンタのネットワークインタフェースカードは、 2 種類に分類することができます。 1 つはスプーラをエミュレートするもの (高価) で、もう 1 つはシリアルやパラレルポートを使うように プリンタにデータを送ることができるだけのもの (安価) です。この節では、 後者の使い方を説明します。前者のプリンタは、前節「<<printing-advanced-network-rm, リモートホストに接続されたプリンタ>>」 の方法が適用できます。

[.filename]#/etc/printcap# ファイルでは、 シリアルかパラレルのインタフェースのどちらを使うのか、 そして、(シリアルインタフェースを使う場合) そのボーレートはいくらであるか、フロー制御は使うのか、 タブのための遅延を加えるのか、 改行文字を変換するかなどの指定をおこなうことができます。 しかし、TCP/IP や他のネットワークポートからデータを受け取るプリンタを 接続するための指定をおこなうことはでき ません。

ネットワーク接続されたプリンタにデータを送るためには、 テキストフィルタと変換フィルタから呼び出すことができる 通信プログラムを開発する必要があります。以下に、 そのようなプログラムの例を示します。スクリプト `netprint` では、 標準入力から印字データをすべて受け取り、 ネットワーク接続されたプリンタにこれを送ります。 `netprint` の最初の引数でプリンタのホスト名を、 2 番目の引数で接続するポート番号を指定します。 このプログラムでは単方向通信 (FreeBSD からプリンタ) のみをサポートしていることに注意してください。 ネットワークプリンタの多くは双方向通信をサポートしていますので、 その恩恵 (プリンタの状態を得たり、 課金をおこなうなど) にあずかりたいと思われるかもしれません。 

[.programlisting]
....
#!/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);

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;
....

このスクリプトは、 様々なフィルタが利用することができます。仮に、Diablo 750-N ラインプリンタを持っており、 これがネットワークに接続されているとしましょう。 プリンタはポート番号 5100 にて印字するデータを受け取ります。 プリンタのホスト名は `scrivener` とします。このとき、 このプリンタのテキストフィルタは次のようになります。

[.programlisting]
....
#!/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
....

[[printing-advanced-restricting]]
=== プリンタの利用に制約を与える

本節では、プリンタの利用に制約を与えるための情報を記しています。 LPD システムでは、プリンタ (ローカル、 リモートのいずれに接続されていても) にアクセスできる人を制限する機能、 複数部のコピーの印字の可否を制御する機能、 ジョブのサイズの最大値やプリンタキューに入る ジョブの最大個数を制御する機能を提供しています。

[[printing-advanced-restricting-copies]]
==== 複数部のコピーの印字を制限する

LPD システムではユーザが複数部のコピーの印字を簡単におこなう 機能を提供しています。ユーザが、(たとえば) `lpr -#5` コマンドを使ってジョブを印字すると、 ジョブのそれぞれのファイルのコピーを 5 部得ることができます。 これがよい機能であると思うかどうかは人それぞれでしょう。

複数部のコピーの印字によってプリンタが 必要以上に消耗してしまうと感じるならば、 [.filename]#/etc/printcap# ファイルに `sc` 項目を加えてください。これにより、 man:lpr[1] の `-#` オプションの使用が禁止されます。 このオプションが指定されているにも関らず、 `-#` オプションを使うと、 次のようなメッセージが表示され、 このオプションの利用できない旨を伝えます。

[source,shell]
....
lpr: multiple copies are not allowed
....

リモートホストからプリンタをアクセスできる 設定にしている場合 (この 設定については、「<<printing-advanced-network-rm, リモートホストに接続されたプリンタ>>」 をご覧ください)、そのリモートホストの [.filename]#/etc/printcap# にも同じように `sc` 項目を追加する必要があることに注意してください。 そうしないと、ユーザは別なホストから複数部のコピーの 印字をすることができてしまいます。

例を使って説明しましょう。次に示す [.filename]#/etc/printcap# ファイルは、ホスト `rose` のものです。プリンタ `rattan` は極めて頑丈なので、 複数部のコピーの印字は許可されています。しかし、 レーザプリンタの `bamboo` はもう少しデリケートで、 このプリンタから複数部のコピーを印字することを `sc` 項目を追加することで禁止しています。

[.programlisting]
....
#
#  /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/ttyu5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:
....

さらに、orchid の [.filename]#/etc/printcap# にも 

....
sc
....

項目を追加する必要があります (`orchid` でこの編集をおこなっているときに、ついでに、プリンタ `teak` でも複数部のコピーの印字を禁止することにしましょう)。

[.programlisting]
....
#
#  /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 -#` の使用を防ぐことができます。しかし、この状態では man:lpr[1] を複数回起動したり、 1 回のジョブで次のように同じファイルを複数個指定することを防ぐまでには至っていません。

[source,shell]
....
% lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign
....

このような悪用を防ぐ方法は (その指示を無視することも含めて) たくさんあります。 各自で調べてみてください。

[[printing-advanced-restricting-access]]
==== プリンタを使用できる人を限定する

それぞれのプリンタを使用できる人を限定するには、UNIX(R) の グループ権限のメカニズムを利用し、さらに、 [.filename]#/etc/printcap# で `rg` 項目を指定することでおこないます。 あるプリンタにアクセスさせてもよいと思うユーザすべてを グループのどれかに入れてください。そして、 そのグループ名を `rg` で指定します。

このとき、そのグループに含まれないユーザ (`root` も含みます) がプリントしようとすると、次のようなメッセージが表示されます。

[source,shell]
....
lpr: Not a member of the restricted group
....

`sc` (suppress multiple copies : 複数部のコピーの印字を禁止する) を指定するときと同様に、`rg` が指定されたプリンタがリモートホストからもアクセスでき (この設定については、 「<<printing-advanced-network-rm, リモートホストに接続されたプリンタ>>」 をご覧ください)、かつ、 そのホストでもプリンタを使用できる人を限定するのが 妥当であると思う場合は、 そのホストの [.filename]#/etc/printcap# にも _rg_ 指定をおこなう必要があります。

たとえば、プリンタ `rattan` は誰でも利用できるが、`bamboo` はグループ `artists` に属している人のみが利用できるようにしてみましょう。 以下に、もうお馴染みとなったホスト `rose` の [.filename]#/etc/printcap# を示します。

[.programlisting]
....
#
#  /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/ttyu5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:
....

これ以外の [.filename]#/etc/printcap# ファイル (ホスト `orchid` のもの) はそのままにしておくことにします。もちろん、 `orchid` のユーザは全員 `bamboo` を利用することができます。これは、 `orchid` には特定のユーザのみにしかアクセスさせておらず、 そのユーザにはプリンタを利用させたいと思っているからなのかもしれませんし、 そうでないかもしれません。

[NOTE]
====
1台のプリンタを複数グループのユーザに利用させることはできません。
====

[[printing-advanced-restricting-sizes]]
==== 入力可能なジョブのサイズを制限する

たくさんのユーザからプリンタが利用される場合には、多分、 ユーザが印字要求を出すことができるファイルのサイズに 上限値を置く必要が生じるでしょう。結局のところ、 スプーリングディレクトリ が置かれているファイルシステムの空き容量がその 上限値になる訳ですが、 あるユーザがこれを独占的に使用すること避けるために、 他ユーザからのジョブ用の空き容量を確保する必要もあります。

LPD では、`mx` 項目を指定することにより、 ジョブ中の個々のファイルのサイズの上限値を制限する機能を提供しています。 指定される ファイルサイズの単位は BUFSIZ ブロックで、1 `BUFSIZ` ブロックは 1024バイトを表わします。この `mx` 項目の値として 0 が指定されると、 ファイルサイズの制限はなくなります。 `mx` が指定されない場合は、 デフォルトの制限として 1000 ブロックが使われます。 

[NOTE]
====
この制限はジョブ中の各 __ファイル__に対して適用されるものであり、 ジョブ全体のサイズ を制限するものでは__ありません__。
====

ところで、 プリンタに設定された上限値を超えるファイルサイズの ファイルが入力された場合でも、LPD はこれを拒否しません。その代わりに、このファイルは、 その先頭から上限値のファイルサイズまでしかキューに入れられません。 そして、その部分までが印字され、 残りの部分は捨てられます。 これが正しい動作といえるのかどうかは議論の余地があるところです。

それでは、設定例に登場しているプリンタ `rattan` と `bamboo` の印字可能なファイルサイズに制限を加えてみましょう。 `artists` グループの人達が作る PostScript(R) ファイルのサイズは 巨大になる傾向があるので、上限値を 5M バイトとします。 それから、 プレインテキスト用のラインプリンタは無制限とします。

[.programlisting]
....
#
#  /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/ttyu5:ms#-parenb cs8 clocal crtscts:rw:\
        :if=/usr/local/libexec/psif:\
        :df=/usr/local/libexec/psdf:
....

この場合もそうですが、この制限はローカル (ホスト rose) のユーザのみに適用されます。 リモートホストからプリンタを利用できるように設定している場合は、 そのリモートホストのユーザはこの制限を受けません。 これらのユーザにも制限を加える場合は、リモートホストの [.filename]#/etc/printcap# の `mx` を指定する必要があります。 リモートホストから印字するための詳しい情報については、 「<<printing-advanced-network-rm, リモートホストに接続されたプリンタ>>」 を参照してください。

リモートホストに接続されたプリンタへのジョブの サイズを制限する特別な方法は他にもあります。これについては、 「<<printing-advanced-restricting-remote, リモートホストからの利用を制限する>>」 を参照してください。

[[printing-advanced-restricting-remote]]
==== リモートホストからの利用を制限する

LPD スプーリングシステムでは、 リモートホストから要求されたジョブの印字を制限するための方法がいくつか提供されています。

ホストの制限::
ローカルの LPD が印字要求を受け付けるリモートホストは、ファイル [.filename]#/etc/hosts.equiv# と [.filename]#/etc/hosts.lpd# によって制御することができます。LPD では、あるホストから印字の要求がきたとき、 このホストの名前がこれら 2 つのファイルのどちらかに含まれている かどうかを調べます。これが含まれていない場合は、LPD はこの要求を拒否します。
+
これらのファイルの形式は単純です。 各行にホストの名前を 1つずつ書いていきます。ファイル [.filename]#/etc/hosts.equiv# の方は man:ruserok[3] プロトコルでも利用され、 man:rsh[1] や man:rcp[1] といったプログラムの動作に影響するので注意が必要です。 [.filename]#/etc/hosts.equiv# の記述は慎重におこないましょう。
+
例として、以下にホスト `rose` の [.filename]#/etc/hosts.lpd# を示します。 
+
[.programlisting]
....
orchid
violet
madrigal.fishbaum.de
....
+
この例では、`rose` はホスト `orchid`, `violet` そして `madrigal.fishbaum.de` からの要求を受け付けることになります。 その他のホストが `rose` の LPD にアクセスしようとしても、 LPD はそのジョブを拒否します (訳注: 拒否されるのは、そのホストが [.filename]#/etc/hosts.equiv# にも含まれていない場合です)。

サイズの制限::
スプーリングディレクトリがある ファイルシステムに残しておく必要がある 空き容量の大きさを制御することができます。 ローカルプリンタ用のスプーリングディレクトリに [.filename]#minfree# という名前のファイルを作成します。そして、 そのファイルの中にリモートホストからのジョブの 要求を受け付けるために必要な空き容量のディスクブロックサイズ (1 ディスクブロック = 512 バイト) を記します。
+
これで、 リモートホストのユーザにファイルシステムを満杯にされないことが保証されます。 この機能を使うと、 ローカルホストのユーザに対してある種の優先権を与えることもできます。 ローカルホストのユーザは、 [.filename]#minfree# ファイルで指定された値よりもディスクの空き容量が下回った後でもずっと、 ジョブをキューに入れることができるのです。
+
たとえば、プリンタ `bamboo` 用の [.filename]#minfree# を作ってみましょう。 このプリンタのスプーリングディレクトリを調べるために、 [.filename]#/etc/printcap# を調べてみましょう。 以下に、`bamboo` のエントリ部分を示します。
+
[.programlisting]
....
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:
....
+
スプーリングディレクトリは `sd` 項目で指定されます。LPD がリモートホストからのジョブを受け付けるために必要な ファイルシステムの空き容量を 3M バイト (= 6144 ディスクブロック) にすることにしましょう。 
+
[source,shell]
....
# echo 6144 > /var/spool/lpd/bamboo/minfree
....

利用ユーザの制限::
[.filename]#/etc/printcap# の `rs` 項目を指定することで、 ローカルプリンタを利用できるリモートホストのユーザを制限することができます。 ローカルホストに接続されたプリンタ用のエントリに `rs` 項目が指定されている場合、 LPD は、印字を要求したユーザのアカウントと同じログイン名が ローカルホストに登録されている__場合に限り__、 そのジョブを受け付けます。それ以外のジョブを LPD は拒否します。
+
この機能は、(たとえば) 複数の部署がネットワークを共有しており、 この内のあるユーザが部署の境界を越えて活動している場合には特に有用です。 そのようなユーザに対して、システムのアカウントを与えるだけで、 これらのユーザは自分が所属する部署のシステムから そのシステムに接続されているプリンタを使用することができます。 これらのユーザにはむしろ、 プリンタの使用__だけ__を認め、 その他のコンピュータ資源を利用させたくないときは、 それらのユーザにはホームディレクトリを与えず、 ログインシェルはシェルとしては何の役にも立たない [.filename]#/usr/bin/false# などを指定して、 これらのユーザのアカウントはプリンタ用の "形式的な" ものとします。

[[printing-advanced-acct]]
=== プリンタの利用に対する課金

という訳で、印字するためには料金をとることが必要です。 取らない理由などありましょうか。紙やインクにはお金がかかります。 そして、プリンタの維持費もかかります。 プリンタには可動部分が搭載されており、 これらの部分は壊れやすいという傾向があります。 プリンタや、その利用形態、維持費について調査をし、1 ページ (1 フィート、1 メートルなど) 当たりにかかるコストを調べておいてください。 これに基づき、プリンタの利用に対する課金を、実際に、 どのように始めればよいのでしょうか。

さて、残念ながら、この部分に関しては LPD スプーリングシステムはほとんど役に立ちません。 課金は使用しているプリンタの種類、印字するもののファイルの形式、 プリンタの利用に対する課金での __あなた自身の__要求に大きく左右されます。

課金システムを実現するためには、プリンタのテキストフィルタ (プレインテキストのジョブに対して課金するため) と変換フィルタ (その他のファイル形式に対して課金するため) を変更して、 印字したページを数えたり、 プリンタに印字したページ数を取得するための要求を送る必要があります。 ただし、出力フィルタのみを利用している場合は、 課金をおこなうことができません。フィルタに関しては、 「<<printing-advanced-filter-intro, フィルタ>>」をご覧ください。

一般に、課金方式には次の 2 つがあります。

* _定期的に課金する方法_ はよく利用される方法です。この理由は、 恐らく比較的簡単に実現できるからです。 誰かがジョブを印字する度に、フィルタはそのユーザ名、 ホスト名、印字したページ数を課金データファイルに記録します。 毎月、毎学期、毎年、その他お好みの時期に、 各プリンタの課金用ファイルを集め、 それぞれのユーザが印字したページ数を合計して その分の課金をおこないます。 次回の課金期間をデータを 0 にして課金を再開するために、 すべてのログファイルを削除します。
* _利用毎に課金する方法_ はあまり利用されていません。これは、 実現するのが比較的難しいからです。この方式では、 プリンタを使用したらすぐに、 フィルタがユーザにその利用に対する課金をおこないます。 ディスククォータのように、課金作業は瞬時におこなわれます。 この方式では、ユーザのアカウントが赤字になる場合に、 ユーザが印字をおこなうことを拒否することができます。 また、ユーザに "プリンタ版 quota" を調べたり、 調整したりする方法を提供したいと思うかもしれ ません。 これを実現するためには、ユーザとその quota を追跡するために、 あるデータベース用のコードが必要となります。

LPD スプーリングシステムでは、 どちらの方式にも簡単に対応できます。(ほとんどの場合は) フィルタを用意しなければならないので、 課金作業のためのコードも用意しなければなりません。 しかし、明るい面もあります。 それは、課金方式に関して、非常に大きな柔軟性が与えられたということです。 たとえば、「定期的に課金する方法」か、 「利用毎に課金する方法」のどちらかを選びまず、そして、 どんな情報 (ユーザ名、ホスト名、ジョブのタイプ、印字された頁数、 使用した紙の大きさ、印字をするために要した時間など) をログに記録するかを決めます。 以上のことをおこなうには、上記の情報を保持するために、 フィルタを変更しなくてはなりません。

==== 手軽なプリンタ課金方法

FreeBSD には、「定期的に課金する方法」による課金を すぐに設定できるように、2 個のプログラムを添付しています。 その内の1つはテキストフィルタ `lpf` で、 これについては、「<<printing-advanced-lpf, テキストフィルタ lpf>>」をご覧ください。もう1つは、 man:pac[8] で、 これはプリンタの課金データファイルからのエントリを集め、 これを合計するプログラムです。

「<<printing-advanced-filters, フィルタはどのように機能しているか>>」で述べたように、 LPD ではテキストフィルタや変換フィルタを起動しますが、 そのコマンドラインで使用している課金データファイルの名前が指定されます。 両フィルタはこの引数を使って、 どの課金データファイルのエントリに書き込めばよいのかを知ることができます。 このファイルの名前は [.filename]#/etc/printcap# 中の `af` 項目によって指定されます。 このファイルが絶対パ スで指定されない場合は、 スプーリングディレクトリからの相対パスとして扱われます。

LPD は、紙のページの幅と行数 (`pw` と `pl` 項目で 指定される) を引数として `lpf` を起動します。`lpf` フィルタでは、 何ページ印字したかを決定するためにこれらの引数を使用します。 ファイルをプリンタに送った後、 課金情報を課金データファイルに書き込みます。 このファイルは次のようになります。

[.programlisting]
....
2.00 rose:andy
3.00 rose:kelly
3.00 orchid:mary
5.00 orchid:mary
2.00 orchid:zhang
....

課金データファイルはプリンタ毎に分けて作るべきです。 これは、`lpf` にはファイルをロックする機構が組み込まれていないためです。 したがって、`lpf` が 2 つ起動されたとき、 同じファイルに同時に書き込みをおこなった場合、 お互いのエントリを破壊してしまうかもしれません。 課金用ファイルを各プリンタ毎に確実に分けるには、 [.filename]#/etc/printcap# 中の `af=acct` 項目を使います。 そうすれば、それぞれの課金用ファイルがプリンタのスプーリングディレクトリに、 [.filename]#acct# という名称で作成されます。

プリンタの利用に対してユーザに課金する準備ができたら、 man:pac[8] プログラムを実行してください (課金したいプリンタのスプーリングディレクトリに移動した後、 `pac` と入力してください)。 次のような、ドル中心主義の課金リストが表示されます (訳注: ドル中心主義という表現は、 表示がドルで出ることへの著者の皮肉でしょう。 セントがあるので小数点以下が表示されますが、 この機能も日本では邪魔ですね)。

[source,shell]
....
  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
....

man:pac[8] が受け付ける引数には次のようなものがあります。

`-P _printer_`::
プリンタ _printer_ の利用に対する課金リストを作成します。 このオプションは、[.filename]#/etc/printcap# の `af` が絶対パスで指定されていた場合に限り、動作します。

`-c`::
ユーザ名のアルファベット順ではなく、 課金額の低い順にリストを並べます。

`-m`::
課金データファイルにあるホスト名を無視します。 このオプションを使用すると、ホスト `alpha` のユーザ `smith` とホスト `gamma` のユーザ `smith` は同一人物として扱われます。 このオプションが指定されない場合は、 両者は別なユーザとして扱います。

`-p _price_`::
[.filename]#/etc/printcap# の `pc` 項目で指定された値、または、 デフォルトの値 (2 セント) に代わり、紙1ページ、または、 1フィート当たりの価格を指定します。 _price_ として、 浮動小数点数を指定することができます。

`-r`::
リストの並べる順番を逆順にします。

`-s`::
課金リストを作成し、 課金データファイルを削除します。

_name..._::
ユーザ _names_ に対する課金情報のみを表示します。

man:pac[8] が生成するデフォルトのリストには、 各ホストのユーザ別に印字ページ数が表示されます。 (ユーザがサイト内のすべてのホストを使用できるため) ホスト名の情報が意味を持たない場合、 `pac -m` を実行してください。次のようなリストが得られます。

[source,shell]
....
  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
....

課金額を決めるために、 man:pac[8] は [.filename]#/etc/printcap# ファイルの `pc` 項目で指定された値 (デフォルト値は 200、すなわち 1 ページ当たり 2 セント) を使います。この項目で、印字物に課金したい ファと思う 1 ページ当たり、 または、1 フィート当たりの価格を 100 分の 1 セント単位で指定します。 man:pac[8] を `-p` オプション付きで起動すると、 この値を置き換えることができます。 この `-p` オプションで指定する額の単位は、 100 分の 1 セント単位ではなく、ドル単位です。たとえば、次の指定では、 1 ページ当たりの単価が 1 ドル 50 セントになります。

[source,shell]
....
# pac -p1.50
....

このオプションを使うと、 実際の課金額を集計することができます。

最後に、`pac -s` を起動すると、課金情報は課金データ累計ファイルに保存されます。 このファイルの名前は、プリンタの課金データファイルの後ろに `_sum` を付けたものとなります。そして、 課金データファイルは削除されます。次に man:pac[8] が起動されると、 その時点までの累計金額を得るために、 課金データ累計ファイルが読み込まれ、 通常の課金データファイルからの情報に加算されます。

==== 印字されたページ数をどのように数えるか?

課金を、リモートホストからの印字でさえも、 正確におこなうためには、 ジョブで使用された紙が何ページであるかを特定できる必要があります。 このことは、プリンタ利用に対する課金をおこなう上の根本的な問題です。

プレインテキストのジョブの場合、 問題を解決するのはさほど難しくはありません。 ジョブが何行であったかを数え、プリンタがサポートしている紙 1 ページに印字できる最大の行数と比較すればよいのです。 重ね打ちするために利用されるファイル中のバックスペース文字や、 物理的に複数の行に渡る長い論理行に対する取り扱いを忘れずにおこなってください。

(「<<printing-advanced-lpf,テキストフィルタ lpf>>」で紹介した) テキストフィルタ `lpf` では、課金をおこなうときに、 これらの取り扱いをおこなってくれます。 課金をおこなうために必要なテキストフィルタを作成している方は、 `lpf` のソースコードが参考になるでしょう。

これに対して、他のファイル形式の処理はどのようにすれば よいのでしょうか。

まず、DVI から LaserJet, または、DVI から PostScript(R) への変換の場合、フィルタが `dvilj` や `dvips` の 出力メッセージを解析することで、 何ページ分の変換がおこなわれたかを知ることができます。 他のファイル形式とその変換プログラムに関しても、 同様のことができるかもしれません。

しかし、この方式には問題点があります。それは、 変換されたページがすべて印字されるとは限らないということです。 たとえば、プリンタが紙詰まりを起こしたり、トナー切れになったり、 はたまた、爆発したりするかもしれません。 そのような状況により印字が途中で中止されたとしても、この方式では、 ユーザは全ページ分の料金を課されてしまうのです。

それでは、どのような対策をたてることができるのでしょうか。

_正確な_ 課金をおこなうための唯一の__確実な__方法は、 何ページ印字したのかを知らせることができるプリンタを入手し、 これをシリアルポートかネットワークに接続することです。 ほとんどすべての PostScript(R) プリンタではこの概念がサポートされています。 他のプリンタも同様です (Imagen レーザプリンタをネットワーク接続するなど)。 それぞれのプリンタのフィルタを、 ジョブを印字した後で印字ページ数を得るように変更してください。 そして、課金情報はここで得られた値__のみに__ 基づいて記録してください。行数を数えたり、 エラーが生じやすいファイルの調査は必要とされません。

もちろん、 気前よく印字料金をすべて無料にすることもできます。

[[printing-using]]
== プリンタを使う

この節では、FreeBSD で設定したプリンタを使う方法について説明します。 ここでは、ユーザレベルでのコマンドを概説します。

man:lpr[1]::
印字をおこないます。

man:lpq[1]::
プリンタキューを調べます。

man:lprm[1]::
プリンタキューにあるジョブを削除します。

また、「<<printing-lpc,プリンタの管理>>」 節で説明されている管理者用コマンド man:lpc[8] もあり、 プリンタやそのキューの制御のために用いられています。

man:lpr[1]、man:lprm[1]、そして man:lpq[1] の 3 コマンドは、`-P _printer-name_` オプションをとり、これによって、 [.filename]#/etc/printcap# のように操作の対象となる プリンタやキューを指定します。 これによって、様々なプリンタに対してジョブを送る、 取り消す、調査することができます。 `-P` が使われなかった場合は、これらのコマンドは `PRINTER` 環境変数で指定されたプリンタを使用します。 そして、`PRINTER` 環境変数がなかった場合は、 これらのコマンドはデフォルトのプリンタ `lp` を使います。

以下では、_デフォルトプリンタ_ という用語が意味するプリンタは、`PRINTER` 環境変数で指定されたプリンタ、もしくは、`PRINTER` 環境変数がない場合は、`lp` という名前のプリンタです。

[[printing-lpr]]
=== 印字する

ファイルを印字するためには、 次のように入力してください。

[source,shell]
....
% lpr filename ...
....

これにより、 入力されたファイルのそれぞれをデフォルトのプリンタ から印字します。ファイル名が与えられなかった場合、 man:lpr[1] は標準入力から印字するデータを読み込みます。たとえば、 次のコマンドにより、ある重要なシステムファイルが印字されます。

[source,shell]
....
% lpr /etc/host.conf /etc/hosts.equiv
....

印字させるプリンタを選択するためには、 次のように入力します。

[source,shell]
....
% lpr -P printer-name filename ...
....

次の例では、プリンタ `rattan` に、 カレントディレクトリにあるファイルの詳細なリストを印字しています。

[source,shell]
....
% ls -l | lpr -P rattan
....

上記の man:lpr[1] コマンドではファイル名の指定がないので、 `lpr` は標準入力から印字するデータ、 この場合、`ls -l` コマンドの出力、を読み込みます。

man:lpr[1] コマンドでは、 出力の整形を制御したり、ファイル変換を適用したり、 複数部数のコピーを作成したり、 などといた様々な幅広いオプションを受け付けることもできます。 詳細については、 「<<printing-lpr-options, その他の印字オプション>>」をご覧ください。

[[printing-lpq]]
=== ジョブの処理状況を調べる

man:lpr[1] コマンドを使って印字をする場合、プリントしようと するデータは "プリントジョブ" と呼ばれる箱に一緒に置かれ、 これが LPD スプーリングシステムに送られます。 プリンタにはそれぞれジョブ用のキューがあり、 送られてきたジョブはあなたや他のユーザからの別のジョブと一緒にそのキューで並んで、 処理される順番を待ちます。 プリンタは到着順にこれらのジョブの印字をおこないます。

デフォルトプリンタのキューの状態を表示するには、 man:lpq[1] と入力します。プリンタを指定するときは、 `-P` オプションを使います。たとえば、次のコマンド

[source,shell]
....
% lpq -P bamboo
....

は、プリンタ `bamboo` のキューの状態を表示します。この `lpq` コマンドの出力結果の例を次に示します。

[source,shell]
....
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` のキューに 3 つのジョブがあることが分かります。 最初のジョブはユーザ kelly からのものであり、 "ジョブ番号" 9 が割り当てられています。 プリンタのすべてのジョブには一意なジョブ番号が付けられています。 ほとんどの場合、このジョブ番号は無視することができますが、 ジョブをキャンセルするときにはこの番号が必要になります。 このことの詳細については、「<<printing-lprm,ジョブの削除>> 」をご覧ください。

ジョブ番号 9 のジョブは 2 つのファイルを処理します。すなわち、 man:lpr[1] のコマンドラインに複数のファイル名が与えられたときは、 1つのジョブとして扱われるのです。このジョブは、現在、 アクティブジョブ ("Rank" の欄の `active` という後に注目) になっています。 これは、プリンタからそのジョブが現在印字されているはずであることを意味しています。 2 番目のジョブでは、 man:lpr[1] コマンドに標準入力からデータが与えられています。 3番目のジョブはユーザ `mary` から与えられました。 このジョブのサイズはとても大きくなっています。 彼女がプリントしようとしたファイルのパス名はここで表示させるには長すぎるため、 man:lpq[1] コマンドはドットを 3 つだけ表示しています。

man:lpq[1] からの出力で一番最初の行もまた有益な情報を与えています。 この行から、プリンタが現在何をしているか (あるいは、少なくとも LPD がプリンタがしていると思っていること) が分かります。

man:lpq[1] コマンドは `-l` オプションもサポートしています。 これにより、 詳しい情報が表示されます。 `lpq -l` の実行例を次に示します。

[source,shell]
....
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
....

[[printing-lprm]]
=== ジョブの削除

印字するようジョブを 送った後で印字を中断したくなったときは、 man:lprm[1] コマンドで、 キューの中からそのジョブを削除することができます。 大抵の場合、アクティブジョブでさえも man:lprm[1] を使って削除することができますが、 そのジョブの一部またはすべてが印字されてしまうかもしれません。

デフォルトプリンタへのジョブを削除するためには、最初に、 man:lpq[1] を使ってそのジョブ番号を調べます。 すなわち、それから、 次のように入力して、ジョブを削除します。

[source,shell]
....
% lprm job-number
....

特定のプリンタへのジョブを削除するときは、 `-P` オプションを使ってそのプリンタを指定します。 たとえば、プリンタ `bamboo` のキューからジョブ番号 10 のジョブを削除するには次のようにします。

[source,shell]
....
% lprm -P bamboo 10
....

man:lprm[1] コマンドには略記法がいくつかあります。

lprm -::
あなたが (デフォルトプリンタへ) 送ったジョブをすべて削除します。

lprm _user_::
ユーザ _user_ が (デフォルトプリンタへ) 送ったジョブをすべて削除します。 他のユーザのジョブを削除できるのはスーパユーザだけです。 あなたは、あなた自身のジョブしか削除することはできません。

lprm::
ジョブ番号もユーザ名もシンボル ``-``も指定されないときは、 man:lprm[1] は現在のアクティブジョブを、 そのジョブを送ったのがあなた自身であるときに限り、 デフォルトプリンタから削除します。ただし、 スーパユーザは任意のアクティブジョブを削除することができます。

上記の略記法をデフォルトプリンタではなく 特定のプリンタに対しておこなうときは、`-P` オプションでそのプリンタを指定するだけよいのです。たとえば、 プリンタ `rattan` のキューへあなたが送ったジョブを すべて削除するためには次のようにします。

[source,shell]
....
% lprm -P rattan -
....

[NOTE]
====
ネットワーク環境で作業をしている場合、 あるホストから送られたプリンタジョブは、これを送ったホストで man:lprm[1] を使った場合に限って、 これを削除することができます。 他のホストで同じプリンタを使えたとしても、 このジョブを削除することはできません。 次の例では、他ホストからジョブを削除することを試みています。

[source,shell]
....
% 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
....

====

[[printing-lpr-options]]
=== その他の印字オプション

man:lpr[1] コマンドには、テキストの整形や、 図や他のファイル形式の変換、複数部コピーの生成、 ジョブの扱いなどを制御することができます。 この節では、これに関するオプションについて記しています。

[[printing-lpr-options-format]]
==== 整形と変換に関するオプション

以下の man:lpr[1] 用のオプションはジョブにおける ファイルの整形の制御に関するものです。 このオプションは、ジョブにプレインテキストが含まれない場合や man:pr[1] ユーティリティを使ってプレインテキストを整形する場合に用いてください。

次の例では、プリンタ `bamboo` に (TeX 組版システムによる) DVI ファイル [.filename]#fish-report.dvi# を印字しています。

[source,shell]
....
% lpr -P bamboo -d fish-report.dvi
....

このオプションは、 ジョブに含まれるすべてのファイルに対して適用されます。 したがって、1 つのジョブに (たとえば) DVI ファイルと ditroff ファイルを混在させることはできません。その代わりに、 ファイルを形式毎に別々のジョブに分け、 それぞれのジョブでその形式用の変換オプションを使って印字してください。

[NOTE]
====
`-p` と `-T` を除くすべてのオプションを使用 するためには、 出力先プリンタ用の変換フィルタが必要です。たとえば、 `-d` オプションを使用するには、DVI 用の変換フィルタが必要 です。詳細については、「<<printing-advanced-convfilters, 変換フィルタ>>」で説明しています。
====

`-c`::
cifplot ファイルを印字します。

`-d`::
DVI ファイルを印字します。

`-f`::
FORTRAN プログラムを印字します。

`-g`::
plot のデータを印字します。

`-i _number_`::
出力に対して、_number_ カラム分の字下げをおこないます。 _number_ が省略されると、 8 カラム分字下げされます。 このオプションはある変換フィルタと一緒の指定されたときのみに機能します。
+
[NOTE]
====
`-i` と数字の間に空白を入れてはいけません。
====

`-l`::
制御文字を含む文字通りのテキストデータを印字します。

`-n`::
ditroff (device independent troff) データを印字します。

-p::
印字する前に man:pr[1] によってプレインテキストを整形します。 詳細については man:pr[1] をご覧ください。

`-T _title_`::
man:pr[1] コマンドにより生成されるヘッダを、 ファイル名の代わりに _title_ とする。 このオプションは、`-p` と一緒に使ったときのみ機能する。

`-t`::
troff データを印字します。

`-v`::
ラスタのデータを印字します。

次の例では、man:ls[1] のマニュアルを美しく整形したものをデフォルトプリンタで印字しています。 

[source,shell]
....
% zcat /usr/shared/man/man1/ls.1.gz | troff -t -man | lpr -t
....

man:zcat[1] コマンドで man:ls[1] のマニュアルのソースファイルの圧縮を復元し、これを man:troff[1] コマンドに渡しています。 これによりソースファイルが整形され GNU troff の形式となります。 その結果は man:lpr[1] に渡され、 LPD スプーラへジョブの要求が発せられます。 man:lpr[1] には `-t` オプションが使われているため、 スプーラでジョブを印字したときに GNU troff の形式から、デフォルトプリンタが解釈できる形式へと変換されます。

[[printing-lpr-options-job-handling]]
==== ジョブに関するオプション

以下のオプションは、man:lpr[1] によって、 そのジョブを特殊な扱いにするよう LPD に指示するためのものです。

-# _copies_::
ジョブに含まれるファイルのそれぞれを 1 部だけ印字するのではなく、 _copies_ 部のコピーを生成させるものです。管理者によっては、 プリンタの消耗を避け、コピー機による複製を奨励するために このオプションの使用が禁止されているかもしれません。 これに関しては、「<<printing-advanced-restricting-copies, 複数部のコピーの印字を制限する >>」をご覧ください。
+
次の例では、デフォルトプリンタで [.filename]#parser.c# を 3 部コピーし、次に、 [.filename]#parser.h# を 3 部コピーしています。
+
[source,shell]
....
% lpr -#3 parser.c parser.h
....

-m::
印字ジョブが完了した後で、メールを送ります。 このオプションを付けると、LPD システムはジョブの処理が終了したときに、 あなたのアカウントにメールを送ります。 メールのメッセージには、ジョブが正常終了したのか、あるいは、 何か異常があり、(しばしば) その異常が何であったのかが書かれています。

-s::
印字ファイルをスプールディレクトリにコピーせず、 代わりに、 シンボリックリンクを作成するよう指示します。
+
印字させるジョブのサイズが大きいとき、 このオプションを使うと便利かもしれません。このオプションにより、 スプー ルディレクトリの容量が節約されます (それに、 巨大なジョブのお陰でスプールディレクトリのあるファイルシステムの空き容量がなくなってしまうかもしれません)。 さらに、LPD がいちいちすべてのデータをコピーする必要がなくなりますので、 時間の節約にもなります。
+
ただし、欠点もあります。LPD はオリジナルのファイルを直接参照するので、 印字が終了するまでそのファイルを変更したり削除することができません。
+
[NOTE]
====
リモートのプリンタで印字している場合、 LPD は、結局のところ、 ローカルホストからリモートホストにファイルをコピーする必要があります。 したがって、`-s` オプションはローカルのスプーリングディレクトリの空き容量を節約するだけで、 リモート側では節約されません。 それでも、このオプションは有用です。
====

-r::
ジョブに含まれるファイルを、 スプーリングディレクトリに ファイルをコピーした後に削除します。もしくは、 `-s` オプションと一緒に使われた場合は、 印字終了後に削除されます。 このオプションの使用には十分注意して下さい。

[[printing-lpr-options-misc]]
==== ヘッダページ用オプション

以下のオプションにより、 ジョブのヘッダページに通常印字さ れるテキストを man:lpr[1] に調整させることができます。 対象のプリンタからヘッダページが出力されない場合は、 これらのオプションは何の効力も持ちません。 ヘッダページの設定に関する情報については、 「<<printing-advanced-header-pages, ヘッダページ>>」を参照してください。

-C _text_::
ヘッダページに印字されるホスト名を _text_ に置き換えます。なお、 ホスト名の場所には、通常、 ジョブの要求があったホストの名前が印字されます。

-J _text_::
ヘッダページに印字されるジョブ名を _text_ に置き換えます。 ジョブ名の場所には、通常、ジョブの最初のファイル名、 または、標準入力からデータが印字されたときは [.filename]#stdin# が印字されます。

-h::
ヘッダページの出力を禁止します。
+
[NOTE]
====
サイトによっては、 そのヘッダページの生成方法により、 このオプションの効果が現れないかもしれません。 詳細は、「<<printing-advanced-header-pages, ヘッダページ>>」をご覧ください。
====

[[printing-lpc]]
=== プリンタの管理

プリンタの管理者として、プリンタの設置、設定、 そして、それらのテストをおこなう必要がありました。 man:lpc[8] コマンドにより、 これまでとは別な管理方法がプリンタと対話的におこなわれます。 man:lpc[8] により、次のことが可能となります。

* プリンタの起動、停止をおこなう。
* キューへの入力の許可、禁止をおこなう。
* それぞれのキューにあるジョブの順番を変更する。

最初に用語に関する注意をしておきます。 プリンタが__停止している__とは、 キューの中にあるどのジョブも印字されることがない状態 を言います。この状態においても、 ユーザはまだジョブの要求をおこなうことができますが、 これらのジョブはキューの中で、 プリンタが__スタートする__状態になるまで、 あるいは、キューの内容が削除されるまで待たされることになります。

キューが__禁止状態__にあると、 (`root` 以外の) すべてのユーザがプリンタにジョブを要求することができません。 キューが__許可状態にある__場合は、 ジョブの入力が許可されます。 キューが__禁止状態にある__場合でも、 プリンタを__スタートす る__状態にすることは可能です。この場合は、 キューが空になるまで、 キュー内のジョブの印字が続けられます。

一般的に、man:lpc[8] コマンドを使用するには `root` 権限を持っている必要があります。 一般のユーザも man:lpc[8] コマンドを使うことはできますが、 プリンタの状態を取得することとハングしたプリンタ を再スタートすることだけに使用が制限されています。

以下に、 man:lpc[8] コマンドに関する説明の要約を述べます。 ほとんどのコマンドでは、操作対象となるプリンタを指定するため _printer-name_ 引数を与えます。 _printer-name_ の代わりに `all` が与えられると、操作は [.filename]#/etc/printcap# 内にある全プリンタに対しておこなわれることになります。

`abort printer-name`::
現在のジョブをキャンセルし、プリンタを停止させます。 キューが許可状態にある場合は、 ユーザはまだジョブを入力することができます。

`clean printer-name`::
プリンタのスプーリングディレクトリから、 ジョブの古いファイルを削除します。状況によって、 とりわけ、印字途中でエラーが発生していたり、 管理操作が頻発していた場合には、 ジョブで作られたファイルを LPD が完全に削除しないことがあります。このコマンドでは、 スプーリングディレクトリに入っていないファイルを見つけ出し、 それを削除しています。

`disable printer-name`::
キューに新しいジョブを入れることを禁止します。 プリンタが動作しているときは、 キューに残っているジョブの印字は続けられます。ただし、 キューが禁止状態にあったとしても、スーパーユーザ (`root`) は常にジョブを入力することができます。
+
このコマンドは、 新しいプリンタやフィルタを設置している間に使用すると有用です。 すなわち、キューを禁止状態にしておくと、 `root` によるジョブのみが入力されます。 そして、他のユーザは、テストが完了し、 `enable` コマンドでキューが再度許可状態になるまで、 ジョブの入力はできなくなります。

`down printer-name message`::
プリンタをダウンさせます。これは、 `disable` をおこなった後で、 `stop` をおこなった場合と等価になります。 _message_ は、ユーザが man:lpq[1] コマンドでプリンタのキューの状態を調べたり、 `lpc status` でプリンタの状態を調べたときに、 プリンタの状況として表示されるメッセージです。

`enable printer-name`::
プリンタのキューを許可状態にします。 ユーザはジョブの入力ができるようになりますが、 プリンタがスタートの状態になるまでは、 プリンタからは何も印字されません。

`help command-name`::
_command-name_ コマンドのヘルプメッセージを表示します。 _command-name_ が指定されなかった場合は、 利用できるコマンドの要約が表示されます。

`restart printer-name`::
プリンタをスタートさせます。通常のユーザは、 LPD がある異常な状況でハングしたときに限り、 このコマンドを使用することができます。しかし、 `stop` または `down` コマンドにより、 停止状態にあるプリンタをスタートさせることはできません。 `restart` コマンドは、 `abort` の後に `start` をおこなったことと同じになります。

`start printer-name`::
プリンタをスタートさせます。 プリンタのキューにあるジョブを印字することでしょう。

`stop printer-name`::
プリンタを停止します。プリンタは、 現在のジョブを終了させ、そして、 キューにあるその他のジョブは印字しません。 プリンタが停止状態にあったとしても、まだ、 許可状態にあるキューに対して、ジョブを送ることができます。

`topq printer-name job-or-username`::
_printer-name_ のキューに対して、ジョブ番号 _job_ のジョブ、または、ユーザ _username_ から送られたジョブを置き換えて、キューの先頭に持ってきます。 このコマンドに関しては、 _printer-name_ の代わりに `all` を使用することはできません。

`up printer-name`::
プリンタをアップ状態にします。これの反対のコマンドが `down` です。`start` の次に `enable` をおこなったことと等しくなります。

コマンドラインから上記のコマンドを入力すると、 man:lpc[8] はこれを受け付けます。コマンドが入力されなかった場合は、 man:lpc[8] は対話モードに入り、 `exit`、`quit`、 または、 ファイル終端文字が入力されるまでコマンドの入力ができます。

[[printing-lpd-alternatives]]
== 標準スプーラの代替品

このマニュアルを最初から通読されている方ならば、ここまでで、 FreeBSD 付属の LPD スプーリングシステムに関して知っておくべきことすべてを学ばれたことと思います。 多分、このシステムにあるたくさんの欠点について認識できたことでしょう。 そこから "(FreeBSD 上で動作する) スプーリングシステムには他にどのようなものがあるのか" という疑問が自然と湧いてきます。

LPRng::
"次世代 LPR" を称するLPRng は、 PLP を完全に書き換えたものです。 Patrick Powell と Justin Mason (PLP の主要な管理者) が共同で LPRng を作成しました。 LPRng の本サイトは http://www.lprng.org/[http://www.lprng.org/] です。

CUPS::
CUPS (the Common UNIX Printing System) は、UNIX(R) ベースのオペレーティングシステムに対して、 移植性の高い印刷レイヤを提供します。 CUPS は Easy Software Products によって、すべての UNIX(R) ベンダとユーザに、 標準的な印刷ソリューションを普及するために開発されています。
+
CUPS は、プリントジョブとキューを管理する基盤として Internet Printing Protocol (IPP) を使っています。機能は限定されますが、 ラインプリンタデーモン (LPD)、 サーバーメッセージブロック　(SMB) や AppSocket (JetDirect とも呼ばれています) プロトコルにも対応しています。 CUPS は、UNIX(R) に現実的なプリント機能を備えるため、 ネットワークプリンタの検索、 PostScript プリンタ記述言語 (PPD) に基づいた印刷オプションを追加します。
+
CUPS のメインサイトは http://www.cups.org/[http://www.cups.org/] です

HPLIP::
HPLIP (the HP Linux(R) Imaging and Printing system) は、 HP アプライアンス用に HP が開発した、 プリンタ、スキャナ、ファックスへの対応のためのプログラム群です。 このプログラムでは、印刷機能において CUPS 印刷システムをバックエンドとして利用しています。
+
HPLIP のメインサイトは、 http://hplipopensource.com/hplip-web/index.html[http://hplipopensource.com/hplip-web/index.html] です。

[[printing-troubleshooting]]
== トラブルシューティング

man:lptest[1] を使った簡単なテストをおこなった結果、 正しい出 力を得られずに、以下に示すような出力が得られるかもしれません。

しばらくしたら出力される、または、 紙の全体が出てこない::
プリンタは上で示されたような印字を おこなったのですが、しばらくして止まってしまい、 動かなくなってしまいました。 印字された結果をプリンタから取り出すためには、 プリンタにある PRINT REMAINING ボタン、または、FORM FEED ボタンを押す必要があるようです。
+
この場合は、 おそらくジョブはプリントをする前に 更にデータが送られてこないか待ち続けているのでしょう。 この問題を解決するためには、プリンタに FORM FEED 文字 (あるいは特定の必要な文字コード) を 送るテキストフィルタを使ってください。 プリンタ内部に残ったデータをプリンタにすぐに印字させるには、 普通はこれで十分です。 次のジョブが前のジョブの最終ページの中央の どこかから印字を開始させないためにも、 紙の途中で印字のジョブが終了したかどうかを確認するのは有益です。
+
シェルスクリプト [.filename]#/usr/local/libexec/if-simple# を次のように変更して、プリンタへジョブを送信した後に FORM FEED 文字を印字させるようにします。
+
[.programlisting]
....
#!/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
....

"階段効果" が現れた::
出力された紙には次のように印字されていました。
+
[source,shell]
....
!"#$%&'()*+,-./01234
                 "#$%&'()*+,-./012345
                                 #$%&'()*+,-./0123456
....
+
あなたは__「階段効果」__ の新たなる犠牲者になってしまいました。この原因は、 改行を表わすべき文字がなんであるか の解釈が混乱していることにあります。UNIX(R) スタイルのオペレーティングシステムでは、改行文字は ASCII コード 10 の line feed (LF) の 1 文字が使われています。MS-DOS(R) や OS/2(R) などは ASCII コード 10の LF _と_、ASCII コード 13 の文字 (carriage return または CR) をペアで使います (訳注: Macintosh では CR のみで表現されています)。大抵のプリンタでは、 改行を表わすために MS-DOS(R) の慣習にしたがいます。
+
FreeBSD で印字する場合、印字したテキストは LF 文字だけ が使われていました。プリンタでは LF 文字を見つけると、紙を 1 行分送り出しました。しかし、 次の文字を印字するた めの紙の水平方向の位置は維持されました。すなわち、CR 文字が意味することは、 次の文字を印字する位置を紙の左端に動かすことです。
+
FreeBSD がプリンタに動作をして欲しいと思っている動作を以下に示します。 
+
[.informaltable]
[cols="1,1", frame="none"]
|===

|プリンタが CR を受け取ったとき
|CR 動作 (復帰) をおこなう

|プリンタが LF を受け取ったとき
|CR + LF 動作 (復帰、改行) をおこなう
|===
+
このように動作させるための方法がいくつかあります。

** これらの文字の解釈を変えるために、 プリンタの設定スイッチかコントロールパネルを操作する方法。 どのようにして設定をするかはプリンタのマニュアルを参照してください。
+
[NOTE]
====
FreeBSD 以外のオペレーティングシステムを切り替えて使う場合、 CR と LF 文字の解釈をそのオペレーティングシステムで使われているようにプリンタを __再設定__する必要があるかもしれません。 以下に示す解決方法のいずれかを 選ぶのがよいかもしれませんね。
====

** 自動的に LF を CR+LF に変換してくれる FreeBSD 用のシリアルドライバを入手する方法。 もちろん、このドライバはプリンタ専用に接続される シリアルポート __のみ__で動作します。 この機能を許可するためには、 `ms#` 項目を使い、 対象プリンタの [.filename]#/etc/printcap# ファイルで``onlcr`` モードを設定します。
** LF 文字の扱いを一時的に変更するための _エスケープコード_ をプリンタに送る方法。 プリンタがサポートしているかもしれないエスケープコード については、 プリンタのマニュアルを参照してください。 適切なエスケープコードが見つかったら、 最初にそのコードを送り、次にプリントジョブを送信 するようにテキストフィルタを変更してください。 
+ 
次に、Hewlett Packard 社の PCL エスケープコードに対応しているプリンタのための テキストフィルタの例を示します。 このフィルタでは、プリンタ に LF 文字を LF と CR の2文字として扱わせます。 その後に、プリンタにジョブを送ります。最後に、 ジョブの最終ページの紙を排出するため、FROM FEED 文字を送ります。このフィルタは Hewlett Packard 社のほとんどすべてのプリンタで機能するはずです。
+
[.programlisting]
....
#!/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 "\f" && exit 0
exit 2
....
+ 
ホスト `orchid` の [.filename]#/etc/printcap# の例を以下に示します。ここには、 一番目のパラレルポートにプリンタ (Hewlett Packard LaserJet 3Si) が一台接続されており、そのプリンタ名は `teak` です。
+
[.programlisting]
....
#
#  /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:
....

[NOTE]
====
LF を CR+LF に置き換える cat コマンドを作る方法も当然考えられます。 そして、このコマンドと、_if-simple_ の cat の部分を置き換えればよいわけです。 具体的にどのようにするかは、 読者への練習問題としましょう。
====

各行が重ね書きされてしまった::
プリンタは紙送りをまったくしませんでした。 テキストすべての行がある行の上で重ねて印字されてしまいました。 
+
この問題は、 階段現象とは "正反対" な問題で、 ほとんどまれにしか起こりません。FreeBSD では行末として扱われる LF 文字が、紙の左端に印字位置を復帰しますが、 紙送りはしない CR 文字として扱われています。
+
プリンタの設定スイッチかコントロールパネルを使って、 LF と CR の文字を次のような解釈をするようにしてください。 
+
[.informaltable]
[cols="1,1", frame="none", options="header"]
|===
| プリンタが受け取ったとき
| プリンタがおこなう

|CR
|CR 動作 (復帰)

|LF
|CR + LF (復帰、改行)
|===
+
[NOTE]
====
LF を CR+LF に置き換える cat コマンドを作る方法も当然考えられます。 そして、このコマンドと、 [.filename]#if-simple# の cat の部分を置き換えればよいわけです。 具体的にどのようにするかは、 読者への練習問題としましょう。
====

プリンタが文字を紛失してしまう::
印字しているのですが、 各行の 2 ～ 3 文字が印字されません。 プリンタを動かせば動かすほど、 もっとたくさんの文字が紛失されていき、 この問題は更に悪くなっていくかもしれませんでした。
+
この問題は、 シリアルポートを通してコンピュータから送られてくるデータの速度に、 プリンタがついていけないことに起因します (この問題は、パラレルポートに接続された プリンタでは発生することはありません)。 この問題を克服する方法が2つあります。

** プリンタが XON/XOFF のフロー制御をサポート している場合は、項目 `ms#` で `ixon` モードをセットして、FreeBSD にこの機能を使用させてください。
** プリンタが Request to Send / Clear to Send ハードウェアハンドシェイク (通称 `RTS/CTS`) をサポートして いる場合は、項目 `ms#` で `crtscts` モードをセットして下さい。それから、 プリンタとコンピュータを接続しているシリアルケーブルが ハードウェアフロー制御用に正しく配線されたものかどうかを確認してください。

プリンタは意味不明な文字列を印字した::
プリンタはランダムなゴミのように 見えるものを印字しましたが、 意図したテキストは印字してくれませんでした。
+
この問題は、通常、 シリアルポートに接続したプリンタでの 通信パラメータの誤りからくる前項とは別の症状です。 `br` 項目の通信速度と `ms#` 項目を再確認してください。 また、プリンタでの設定が [.filename]#/etc/printcap# ファイルで設定した 内容と一致しているかどうかも確認してください。
+
[NOTE]
====
simple-if のような単純なフィルタだけの状態で、 日本語を含むテキストを印字しようとした場合にも、 シリアルポート、パラレルポートの使用に関係なく、 このような症状は見られます。日本語プリンタの場合、 漢字コードそのもの を送信しただけでその漢字を印字してくれるものは、 少なくとも訳者は見たことがありません。 漢字を印字するための制御 コードを別途送信するフィルタが必要となります。 また、そのようなフィルタを使用していても、 そのフィルタが想定してる漢字コードと異なった文書を プリントしようとしたときもこのような症状は出ます。 もちろん、これはプリンタ用の 言語を持たないプリンタの話で、PostScript(R) プリンタ などにプレインテキストを送信しても、日本語対応、 非対応に関らず、意味不明な文字列が印字される (もしくは、何も印字されない) ことでしょう。
====

何も起きない::
もしプリンタが何の動作もしないのであれば、 ハード的な問題ではなく、多分 FreeBSD の中に問題があります。 [.filename]#/etc/printcap# ファイルで、 デバッグしているプリンタのエントリに (`lf` 項目で) ログファイルを取るように 設定を追加してください。たとえば、プリンタ `rattan` 用のエントリの項目 `lf` は次のようになります。
+
[.programlisting]
....
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
....
+
次に、もう一度印字をおこなってみます。そして、 発生したと思われるエラーメッセージを見るためにログファイル (上記の例では、 [.filename]#/var/log/rattan.log#) を調べます。そこで見られたメッセージを元に、 問題を解決してみてください。
+
項目 `lf` が指定されていない場合、LPD はデフォルトのログファイルとして [.filename]#/dev/console# を使います。
