"Modular DocBook HTML Stylesheet Version 1.71 ">

Google

LPRngLogo LPRngTool

The Printing Cookbook

Patrick A Powell

papowell@lprng.com
AStArt Technologies
9475 Chesapeake Dr, Suite D,
San Diego, CA 92123
Phone 858-874-6543
Fax 858-279-8424

This is a set of Recipes for Printing, a set of procedures that can be used to set up and diagnose printing in a range of system environments. The main emphasis will be on using the LPRng print spooler, either by itself or with other print spooling systems.


Table of Contents
Preface
1. Acknowledgements
2. Conventions
3. Disclaimer
1. Introduction - The Basics and Variations
1.1. Checking the Printing System
1.2. Fixing the Problems
2. Simple Spooling
2.1. Setting Up The Print Queues
2.2. Diagnostics for Spooling Problems
2.3. What Went Wrong With My Job?
2.4. Diagnostics for lpd Problems
3. Printers
3.1. Interface
3.2. Parallel Port
3.3. Network Ports
3.4. Sending To SMB (Samba, Microsoft) Printer, Novell, Appletalk
3.5. Serial Port
4. Printer Job Formats
4.1. PostScript
4.2. PCL
4.3. Printer Job Language (PJL) and PostScript, PCL
4.4. Text Files
4.5. Magical Mystery Proprietary Format
4.6. Printing Test Pages
5. Filters
5.1. Writing Your Own Filter
5.2. The LPRng IFHP Filter
5.3. Taming the Wild Phaser Printer
6. Banner Pages and Accounting
6.1. Suppressing Banner Pages
6.2. Forcing Banner Pages
6.3. Generating Banner Pages
6.4. Accounting
6.5. Accounting Gotchas
6.6. Accounting Including Banner Pages
7. Printer Pools and Load Sharing
7.1. Implementing Smart Load Balancing
7.2. Using :chooser Exit Codes
8. Wildcards, Bounce Queues, and Forwarding
8.1. Bounce Queues
8.2. Adding -Z Options Using Bounce Queues
8.3. Adding Options By Modifying Control File
9. Form Support and Hold Queues
9.1. Hold Queues
10. Interfacing to Vintage, Legacy, and SunOS Print Spoolers
11. Managing Enterprise Level Printing Systems
11.1. Templates and Standard Configurations
11.2. Master Print Servers, One User Printcap
11.3. Master Print Servers, Local Spooling
11.4. Master Print Servers, Selection by User
11.5. The Great Grand Dad Of All Printcap Files
11.6. Using Printcap Filters and Central Databases
12. LPRngTool
A. LPRng
A.1. Documentation
A.2. Installation
A.3. License
A.4. Commercial Support
A.5. Web Site, FTP Site, and Mirrors
A.6. Mailing List
A.7. PGP Public Key
B. References and Standards
B.1. RFCs
B.2. PostScript
B.3. HP PCL 5
B.4. HP PJL
B.5. PDF
C. RFC 1179 - Line Printer Daemon Protocol
C.1. Ports and Connections
C.2. Protocol Requests and Replies
C.3. Job Transfer
C.4. Data File Transfer
C.5. Control File Contents
C.6. lpq Requests
C.7. lprm Requests
C.8. LPC Requests
C.9. Block Job Transfer
C.10. Authenticated Transfer
List of Figures
1. lpq status
1-1. Print Spooler Architecture
1-2. Configuration Files
1-3. Printcap
1-4. lpd.conf Defaults File
1-5. lpd.perm Permissions File
1-6. Clients and Configuration Files
1-7. ${HOME}/.printcap Information
1-8. Using checkpc
1-9. Using checkpc -f
2-1. Basic Printcap Entry
2-2. Run checkpc
2-3. Check for Running Server
2-4. Run lpq
2-5. Run lpc
2-6. Run lpr
2-7. Run lprm
2-8. Enable Printing
2-9. Using lpr -V
2-10. The lpr Options
2-11. Debug Options
2-12. The lpr -D1 Output
2-13. Using lpr -Dnetwork
2-14. Debugging lpq
2-15. Basic lpq Information
2-16. Using the lpq -l Option
2-17. Using the lpq -L Option
2-18. Job Completion
2-19. Summary Status Displays
2-20. lpd Options
2-21. Using lpd Debug Options
2-22. Debugging Spool Queue
2-23. Setting Queue Debug Options
2-24. log File
3-1. Printer Types
3-2. Interface Types
3-3. Parallel Port
3-4. Parallel Port Printcap
3-5. Loading Linux Parallel Port Driver
3-6. Parallel Port Problems
3-7. Network Ports
3-8. Network Port Printcap
3-9. Benefits of Network Port Printcap
3-10. Network Print Server
3-11. Using Program To Send To Printer
3-12. Protocols, Packages, and Transfer Programs
3-13. Printcap For Transfer Programs
3-14. Samba smbclient Wrapper
3-15. $PRINTCAP_ENTRY
3-16. Novell and Appletalk Wrappers
3-17. Serial Port
3-18. Serial Port Printcap
4-1. Page Description Lanaguages
4-2. How To Identify Print Formats
4-3. Using the file Application
4-4. One PostScript Page
4-5. Generate One Page
4-6. PostScript Document Structuring Conventions
4-7. Tools for PostScript Document Manipulation
4-8. Selection of Pages + 4up Printing
4-9. PostScript Output
4-10. End Of PostScript Job: ^D (CTRL-D)
4-11. One PCL Page
4-12. Generate One Page
4-13. PJL Example
4-14. Text Files and The Jaggies
4-15. Fixing The Jaggies
4-16. Magical Mystery Formats
4-17. GhostScript To The Rescue
4-18. GhostScript Devices
4-19. GhostScript Support
4-20. Printing Test Pages To Parallel Port
4-21. Using Netcat (nc)
5-1. Filters
5-2. Filter Specification in Printcap Entry
5-3. Specifying Job Datafile Format
5-4. Filter Execution Environment
5-5. Command Line Options
5-6. Filter Exit Codes
5-7. Solid As A Rock Filter Operation
5-8. Solid As A Used Paper Coffee Filter Operation
5-9. Filter Template in perl
5-10. How To Determine The Type of Job File
5-11. Printcap for Filter
5-12. Using Filter With $debug=1
5-13. Using Filter With $debug=0
5-14. ifhp
5-15. ifhp.conf Configuration Information
5-16. Default Printer Magic Cookies
5-17. PostScript Only Printer
5-18. Using the ifhp Filter
5-19. Example of ifhp Operation
5-20. Using -Z to Pass Options to ifhp
5-21. Testing ifhp Operations
5-22. Phaser/Appsocket Support
6-1. Changing JetDirect Configuration
6-2. Printcap Option :sh and lpr -h (No Header) Option
6-3. Removing Banner Lines
6-4. Forcing Banner Pages
6-5. Generating Banner Page
6-6. Basic Accounting Information
6-7. Accounting File Information
6-8. Filter Accounting Information
6-9. Accounting Gotchas
6-10. Accounting Using Banner Pages
7-1. Printer Pools and Load Sharing
7-2. Load Balancing Printcap
7-3. Load Balancing to Remote Queues
7-4. Printcap for Chooser
7-5. Chooser Program Operation
7-6. Filter Template in Perl
7-7. Choosing A Destintation
7-8. Chooser Exit Codes
8-1. Evil (BAD) Way
8-2. Not So Evil Way
8-3. Add Options Using :append_z
8-4. Diabolically Fiendishly Clever Method
8-5. Using update_z
9-1. Hold Queues
9-2. All Hold Queues
9-3. Releasing Jobs for Printing
9-4. Releasing Jobs For Scheduled Print Run
9-5. Using Job Classes
9-6. Setting New Job Classes and Disabling Job Classes
9-7. Modifying Control File Using update_class
9-8. The update_class Filter
10-1. Using :bk (Berkeley Kompatible) Flag
11-1. Templates in Printcaps
11-2. Using lpc client all
11-3. Master User Printcap File, No Local Spooling
11-4. Master User Printcap File, Local Spooling
11-5. Master User Printcap File, No Local Spooling
11-6. All In One
11-7. Printcap Path Configuration Information
11-8. Example of Returned Printcap Value
12-1. Starting Screen
12-2. Printcap Entry Selection
12-3. Add A Printer
12-4. Option Specification
12-5. Advanced Options
12-6. ifhp Options
12-7. Saving Printcap Entry
12-8. Checkpc Results

Preface

A good cookbook will provide the reader not only with a set of recipes that sound delicious but also with a set of instructions that will allow novices to experts to prepare them. Of course, there are cookbooks for novices, cookbooks for experts, and then the gastronmic encyclopedias.

These Recipes for Printing are a collection of old favorites, not of the author, but of the hundreds of users of LPRng and other print spooling systems. They are not a complete discussion of the printing haute cuisine, but deal more with the preparation of the Minnesota Hot Dish. As I find from personal experience, you need to make a casserole for a family dinner far more often than to prepare mijotée de lentilles au lardons, dos de poisson-chat rôti, au vinaigre d'herbes for that one-time special dinner.

The various test files, scripts and examples in this document are also in the LPRng distribution in the /LPRng-xxx/UTILS directory.

Enjoy! Bon Appetite!


1. Acknowledgements

I would like to thank all of the LPRng users who so relentlessly tried an incredible number of permutations and combinations printers, software, and networks, and whose requests for just one more feature led to the development of the LPRng software.


2. Conventions

Many examples will show commands run by ordinary or privleged users. The prompt character will indicate the user:

User Prompt
Normal user host {20} % su
root host {2} #

Recipes and major examples will be show as:

Figure 1. lpq status

    h110: {64} % lpq
    Printer: lp@h110
     Queue: no printable jobs in queue
     Status: job 'cfA711h110.private' removed at 17:11:43.919
     Filter_status: done at 17:11:43.823


Smaller sets of code or commands will be shown as:

    Queue: no printable jobs in queue



3. Disclaimer

THIS DOCUMENTATION AND THE DESCRIBED SOFTWARE AND PROCEDURES IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


Chapter 1. Introduction - The Basics and Variations

Figure 1-1. Print Spooler Architecture

The LPRng print spooling system has the components shown in Figure 1-1. A program generates output and pipes it to the lpr application or the lpr application is used to print a file. The lpr application connects to the lpd print server over a network connection and then transfers the print job data and print options. The lpd server will store the job information Figure 1-2 in a spool directory and when the output device is available will transfer the job to the printing device.

Since the print job may not be in the appropriate format for the ouput device a filter program may be used to prepare the output data or perform special operations on the output device. Alternatively, the print job can be forwarded to another print spooler Figure 1-1, transferred directly to a TCP/IP network port.

Figure 1-2. Configuration Files

As shown in Figure 1-2, the LPRng print spooler uses the /etc/printcap, /etc/lpd.conf, and /etc/lpd.perms, files to get its operational parameters. The the /etc/printcap file defines a set of spool queues, each of which holds print jobs. The a print job consists of a control file (cfAnnnHHHHHHH) and one or more data files (dfAnnnHHHHHHH dfBnnnHHHHHHH, etc); the control file contains information such as the user name, file names, and printing options, while the data files contain the data to be printed.

Figure 1-3. Printcap

    # Common configuration information
    .common:sd=/var/spool/lpd/%P
      :sh:mx=0:force_localhost
    
    # forward to remote spooler
    lp:cm=Default Printer
     :tc=.common
     :lp=raw@10.0.0.1
           #  legacy - :rp=raw:rm=10.0.0.1
    
    # lp0 - open a device
    lp0|aliasforlp0:cm=Parallel Port Printer:\
      :tc=.common:lp=/dev/lpt0:
    
    # lp1 - open a network connection
    lp1:tc=.common:lp=10.0.0.14%9100
    
    # lp2 - run a program
    lp2:tc=.common:lp=|/usr/local/bin/smbprint

The /etc/printcap file format is very simple in appearance but complex in information. By convention, lines starting with # are comments; a printcap entry starts with the entry name followed by one or more aliases, followed by options.

The :tc option specifies a printcap entry for inclusion; there can be more than one entry and they are processed in order that they appear in the :tc list. The other options are processed after the :tc list; this means that the printcap options overide the ones from the :tc list. If a entry name starts with a period (.), then the LPRng system uses it only for :tc lists. This is similar to the use of hidden files, i.e. - files whose names start with a period are not displayed by the ls command.

Figure 1-4. lpd.conf Defaults File

    # Purpose: always print banner, ignore lpr -h option
    #   default ab@ (FLAG off)
    # Purpose: query accounting server when connected
    #   default achk@ (FLAG off)
    # Purpose: accounting at end (see also af, la, ar, as)
    #   default ae=jobend $H $n $P $k $b $t  (STRING)
    # Purpose: name of accounting file (see also la, ar)
    #   default af=acct  (STRING)
    
    # Purpose: use long job number (0 - 999999) when a job is submitted
    #   default longnumber@ (FLAG off)
    longnumber


The /etc/lpd.conf file can be used to override the set of default values for the print spooler or other printing applications. By the way, all of the LPRng options and their default values are defined in this file in the comments.

Figure 1-5. lpd.perm Permissions File

    ACCEPT SERVICE=C SERVER REMOTEUSER=root,papowell
    ACCEPT SERVICE=C LPC=lpd,status,printcap
    REJECT SERVICE=C
    ACCEPT SERVICE=M SAMEHOST SAMEUSER
    ACCEPT SERVICE=M SERVER REMOTEUSER=root
    REJECT SERVICE=M
    DEFAULT ACCEPT

The /etc/lpd.perms file (Figure 1-5) is used by lpd to determine who is allowed to perform various operations. The format of this file is modelled on that of a packet filter. When a request is made, the file is scanned for matches; each match sets a success or fail condition. The success or fail of the last match (or the last default value) will determine whether or not to perform the operation.

Figure 1-6. Clients and Configuration Files

The LPRng client applications lpr, lprm, lpq, and lpc use the /etc/lpd.conf, /etc/printcap and ${HOME}/.printap files (if they exist) (Figure 1-6). The values in the ${HOME}/.printcap file are used to override the values in the /etc/printcap file, and the first printcap entry in the ${HOME}/.printap file becomes the default printer for the user (see Figure 1-7).

Figure 1-7. ${HOME}/.printcap Information

    # force your default printer
    #  - forces first entry to be lp_out
    lp_out:
    
    # send everything to your secret server
    *:lp=%P@secret_server:force_localhost@
    
    # combine the two above:
    lp|*:lp=%P@secret_server:force_localhost@
    
    # and of course, you can specify extra lpr options
    # for those special purpose printers and total abuse
    landscape:lpr= -Zlandscape -Plp

1.1. Checking the Printing System

Figure 1-8. Using checkpc

    h110: {1} % su
    Password:
    h110# checkpc
    h110# checkpd -V
    LPRng-3.7.10, Copyright 1988-2001 Patrick Powell, <papowell@lprng.com>
    Checking for configuration files '/etc/lpd.conf'
      found '/etc/lpd.conf', mod 0100644
    Checking for printcap files '/etc/printcap'
      found '/etc/printcap', mod 0100644
     DaemonUID 1, DaemonGID 1
    Using Config file '/etc/lpd.conf'
    LPD lockfile '/var/run/lpd.515'
    ...
    Checking printer 'lp'
     Checking directory: '/var/spool/lpd/lp'
       directory '/var'
       directory '/var/spool'
       directory '/var/spool/lpd'
       directory '/var/spool/lpd/lp'
      checking 'control.lp' file
      checking 'status.lp' file
      checking 'status' file
      checking 'log' file
      checking 'acct' file

The checkpc utility will read and parse the printcap file. It will report a zillion errors if something is wrong.


1.2. Fixing the Problems

Figure 1-9. Using checkpc -f

    h110: {1} % checkpc
    Warning -  bad directory - /var/spool/lpd/lp
    Warning -   Printer_DYN 'lp' spool dir '/var/spool/lpd/lp' needs fixing
    Warning -  bad directory - /var/spool/lpd/lp0
    Warning -   Printer_DYN 'lp0' spool dir '/var/spool/lpd/lp0' needs fixing
    h110: {2} % su
    Password:
    h110# checkpc -f
    Warning -   changing ownership '/var/spool/lpd/lp' to 1/1
    Warning -   changing ownership '/var/spool/lpd/lp' to 1/1
    Warning -   changing ownership '/var/spool/lpd/lp0' to 1/1
    Warning -   changing ownership '/var/spool/lpd/lp0' to 1/1
    h110# exit
    h110: {3} % checkpc
    h110: {4} % checkpc

The checkpc -f (-f for fix) will make checkpc attempt create missing files, set permissions, and take basic corrective actions. If it fails, then you have probably a very bad /etc/printcap file.


Chapter 2. Simple Spooling

This section covers the basic facilities that you will probably encounter when trying to set up a print queue. We will start with a basic print queue and then run through the setup steps.

Figure 2-1. Basic Printcap Entry

    # Common configuration information
    .common:sd=/var/spool/lpd/%P
      :sh:mx=0:force_localhost
    lp:cm=Default Printer, Forward to remote
     :tc=.common
     :lp=raw@10.0.0.1
    
    # lp0 - open a device
    lp0:cm=Parallel Port Printer
      :tc=.common:lp=/dev/lpt0:

2.1. Setting Up The Print Queues

Figure 2-2. Run checkpc

    h110: {1} % checkpc
    Warning -  bad directory - /var/spool/lpd/lp
    Warning -   Printer_DYN 'lp' spool dir '/var/spool/lpd/lp' needs fixing
    Warning -  bad directory - /var/spool/lpd/lp0
    Warning -   Printer_DYN 'lp0' spool dir '/var/spool/lpd/lp0' needs fixing
    h110: {2} % su
    Password:
    h110# checkpc -f
    Warning -   changing ownership '/var/spool/lpd/lp' to 1/1
    Warning -   changing ownership '/var/spool/lpd/lp' to 1/1
    Warning -   changing ownership '/var/spool/lpd/lp0' to 1/1
    Warning -   changing ownership '/var/spool/lpd/lp0' to 1/1
    h110# exit
    h110: {3} % checkpc
    h110: {4} % checkpc

First, you run checkpc -f. This will tell you if something is wrong with the printcap.

Figure 2-3. Check for Running Server

    h110: {5} % lpc lpd
    Printer 'lp@localhost' - cannot open connection - Connection refused
    Make sure the remote host supports the LPD protocol
    h110: {6} % su
    Password:
    h110# lpd
    h110# lpc lpd
    lpd server pid 6418 on h110.private
    h110# exit
    exit
    h110: {7} % lpc lpd
    lpd server pid 6418 on h110.private

Next, you make sure the lpd server is running, and if it is not, then you restart it.

Figure 2-4. Run lpq

    h110: {373} % lpq -a
    Printer: lp@h110
     Queue: no printable jobs in queue
    Printer: lp0@h110
     Queue: no printable jobs in queue


You now make sure that you can get the print queue status.

Figure 2-5. Run lpc

    h110: {374} % lpc stop lp lp0
    Printer: lp@h110
    lp@h110.private: stopped
    Printer: lp0@h110
    lp0@h110.private: stopped
    h110: {375} % lpq -a
    Printer: lp@h110 (printing disabled)
     Queue: no printable jobs in queue
    Printer: lp0@h110 (printing disabled)
     Queue: no printable jobs in queue

Use lpc to disable printing.

Figure 2-6. Run lpr

    h110: {376} % echo hi >/tmp/hi
    h110: {377} % lpr /tmp/hi
    h110: {378} % lpq
    Printer: lp@h110 (printing disabled)
     Queue: 1 printable job
     Server: no server active
     Rank   Owner/ID          Class Job Files         Size Time
    1      papowell@h110+445    A   445 /tmp/hi          3 17:40:51
    h110: {379} % lpr -Plp0 /tmp/hi
    h110: {380} % lpq -Plp0
    Printer: lp0@h110 (printing disabled)
     Queue: 1 printable job
     Server: no server active
     Rank   Owner/ID          Class Job Files         Size Time
    1      papowell@h110+449    A   449 /tmp/hi          3 17:41:05


Now try spooling a job.

Figure 2-7. Run lprm

    h110: {381} % lprm
    Printer lp@h110:
      checking perms 'papowell@h110+445'
      dequeued 'papowell@h110+445'
    h110: {382} % lprm -Plp0
    Printer lp0@h110:
      checking perms 'papowell@h110+449'
      dequeued 'papowell@h110+449'

Now try removing a job.

Figure 2-8. Enable Printing

    h110: {383} % lpc enable lp lp0
    Printer: lp@h110
    lp@h110.private: enabled
    Printer: lp0@h110
    lp0@h110.private: enabled

Finally, enable printing.


2.2. Diagnostics for Spooling Problems

Figure 2-9. Using lpr -V

    h110: {388} % lpr -V /tmp/hi
    LPRng-3.7.10, Copyright 1988-2001 Patrick Powell, <papowell@lprng.com>
    sending job 'papowell@h110+29' to lp@localhost
    connecting to 'localhost', attempt 1
    connected to 'localhost'
    requesting printer lp@localhost
    sending control file 'cfA029h110.private' to lp@localhost
    completed sending 'cfA029h110.private' to lp@localhost
    sending data file 'dfA029h110.private' to lp@localhost
    completed sending 'dfA029h110.private' to lp@localhost
    done job 'papowell@h110+29' transfer to lp@localhost

The first line of defense is to see what is happening when you try to spool a job. The lpr -V (-V for Verbose) will show a simple high level trace.

Figure 2-10. The lpr Options

    h110: {389} % lpr -=
    lpr: Illegal option '='
    Usage: lpr [-Pprinter[@host]] [-A] [-B] [-Cclass] [-Fformat] [-G] [-Jinfo]
       [-(K|#)copies] [-Q] [-Raccountname]  [-Ttitle]  [-Uuser[@host]] [-V]
       [-Zoptions] [-b] [-m mailaddr] [-h] [-i indent] [-l] [-w width ] [-r]
       [-Ddebugopt ] [--] [ filenames ...  ]
     -A          - use authentication specified by AUTH environment variable
     -B          - filter files and reduce job to single file before sending
     -C class    - job class
     -D debugopt - debugging flags
     -F format   - job format
       -b,-l        - binary or literal format
        c,d,f,g,l,m,p,t,v are also format options
     -G          - filter individual job files before sending
     -J info     - banner and job information
     -K copies, -# copies   - number of copies
     -P printer[@host] - printer on host
     -Q          - put 'queuename' in control file
     -Raccntname - accounting information
     -T title    - title for 'pr' (-p) formatting
     -U username - override user name (restricted)
     -V          - Verbose information during spooling
     -X path     - user specified filter for job files
     -Y          - connect and send to TCP/IP port (direct mode)
     -Z options  - options to pass to filter
     -h          - no header or banner page
     -i indent   - indentation
     -k          - do not use tempfile when sending to server
     -m mailaddr - mail final status to mailaddr
     -r          - remove files after spooling
     -w width    - width to use
     --          - end of options, files follow
     filename '-'  reads from STDIN
     PRINTER, LPDEST, NPRINTER, NGPRINTER environment variables set default printer.
    LPRng-3.7.10, Copyright 1988-2001 Patrick Powell, <papowell@lprng.com>

Use the -= option to see the available options.

Figure 2-11. Debug Options

    h110: {392} % lpr -D=
    debug usage: -D [ num | flag=num | flag=str | flag | flag@ | flag+N ]*
      flags recognized: network[+N,@], database[+N,@], lpr[+N,@],
       lpc[+N,@], lprm[+N,@], lpq[+N,@], log[+N,@],
       test=num

The -D= option shows the debugging flags available.

Figure 2-12. The lpr -D1 Output

    h110: {395} % lpr -D1 /tmp/hi >&/tmp/x
    2001-10-18-05:29:05 [8052]  Initialize: /dev/null fd 3
    2001-10-18-05:29:05 [8052]  initsetproctitle: using builtin
    2001-10-18-05:29:05 [8052] lpr  Setup_uid: OriginalEUID 0, OriginalRUID 1001
    2001-10-18-05:29:05 [8052] lpr  Setup_uid: OriginalEGID 1001, OriginalRGID 1001
    2001-10-18-05:29:05.761 [8052] lpr  Setup_configuration: starting, Allow_getenv 0
    2001-10-18-05:29:05.761 [8052] lpr  Setup_configuration: Configuration file '/etc/lpd.conf'
    2001-10-18-05:29:05.761 [8052] lpr  Setup_configuration: Require_configfiles_DYN '1'
    2001-10-18-05:29:05.761 [8052] lpr  Get_config: required '1', '/etc/lpd.conf'
    2001-10-18-05:29:05.762 h110 [8052] lpr
       Get_local_host: ShortHost_FQDN=h110, FQDNHost_FQDN=h110.private
    2001-10-18-05:29:05.763 h110 [8052] lpr
       Is_server 0, DaemonUID 1, DaemonGID 1, UID 0, EUID 0, GID 1001, EGID 1001
    2001-10-18-05:29:05.763 h110 [8052] lpr
       Setup_configuration: Host 'h110.private', ShortHost 'h110', user 'papowell'
    ...

The lpr -D1 (diagnostic level 1) shows a summary of the various steps taken to send the job. If you want more detail, try lpr -D2; or even lpr -D3;.

Figure 2-13. Using lpr -Dnetwork

    h110: {400} % lpr -Dnetwork /tmp/hi
    lp: getconnection: START host localhost, timeout 10, connection_type 1
    lp: getconnection: fqdn found localhost.my.domain, h_addr_list count 1
    lp: Link_dest_port_num: port 515 = 515
    lp: getconnection: AGAIN port 808, min 512, max 1023, count 0, connects 0
    lp: Link_dest_port_num: port 515 = 515
    lp: getconnection: sock 3, src ip 127.0.0.1, port 808
    lp: getconnection: dest ip 127.0.0.1, port 515
    lp: getconnection: connection to 'localhost' socket 3, errormsg 'No Error'
    lp: Link_send: host 'localhost' socket 3, timeout 6000
    lp: Link_send: str '^Blp
    ', count 4, ack 0xbfbfc3d0
    lp: Link_send: final status NO ERROR
    lp: Link_send: host 'localhost' socket 3, timeout 6000
    lp: Link_send: str '^B142 cfA065h110.private
    ', count 24, ack 0xbfbfbf90
    lp: Link_send: final status NO ERROR
    lp: Link_send: host 'localhost' socket 3, timeout 6000
    lp: Link_send: str 'Hh110.private
    Ppapowell
    J/tmp/hi
    CA
    Lpapowell
    Apapowell@h110+65
    D2001-10-18-05:34:18.939
    Qlp
    N/tmp/hi
    fdfA065h110.private
    UdfA065h110.private
    ', count 143, ack 0xbfbfbf90
    lp: Link_send: final status NO ERROR
    lp: Link_send: host 'localhost' socket 3, timeout 6000
    lp: Link_send: str '^C3 dfA065h110.private
    ', count 22, ack 0xbfbfbf24
    lp: Link_send: final status NO ERROR
    lp: Link_send: host 'localhost' socket 3, timeout 6000
    lp: Link_send: str '', count 1, ack 0xbfbfbf24
    lp: Link_send: final status NO ERROR

The lpr -Dnetwork (network diagnostic level 1) shows the network operations performed by lpr. If you want more detail, try lpr -Dnetwork+2 or even lpr -Dnetwork+3.

Figure 2-14. Debugging lpq

    h110: {1} % lpq -=
    lpq: Illegal option '='
    usage: lpq [-aAclV] [-Ddebuglevel] [-Pprinter] [-tsleeptime]
      -A           - use authentication specified by AUTH environment variable
      -a           - all printers
      -c           - clear screen before update
      -l           - increase (lengthen) detailed status information
                     additional l flags add more detail.
      -L           - maximum detailed status information
      -n linecount - linecount lines of detailed status information
      -Ddebuglevel - debug level
      -Pprinter    - specify printer
      -s           - short (summary) format
      -tsleeptime  - sleeptime between updates
      -V           - print version information
    
    h110: {2} % lpq -D1
    2001-10-18-05:39:09 [8090]  Initialize: /dev/null fd 3
    2001-10-18-05:39:09 [8090]  initsetproctitle: using builtin
    2001-10-18-05:39:09 [8090] lpq  Setup_uid: OriginalEUID 0, OriginalRUID 1001
    ...
    
    h110: {3} % lpq -Dnetwork
    lp: getconnection: START host localhost, timeout 10, connection_type 1
    lp: getconnection: fqdn found localhost.my.domain, h_addr_list count 1
    lp: Link_dest_port_num: port 515 = 515
    lp: getconnection: AGAIN port 862, min 512, max 1023, count 0, connects 0
    lp: Link_dest_port_num: port 515 = 515
    lp: getconnection: sock 3, src ip 127.0.0.1, port 862
    ...

The lpq, lprm, and lpc applications also support the -= and -D (debug) options.


2.3. What Went Wrong With My Job?

Figure 2-15. Basic lpq Information

    
    h110: {1} % lpr /tmp/hi
    h110: {1} % lpq
    Printer: lp@h110
     Queue: 1 printable job
     Server: pid 8741 active
     Unspooler: pid 8742 active
     Status: processing 'dfA740h110.private', size 3, format 'f',
        IF filter 'ifhp' at 08:16:58.465
     Filter_status: code = 10003, 'Warming Up' at 08:17:02.045
     Rank   Owner/ID         Class Job Files      Size Time
    active papowell@h110+740  A    740 /tmp/hi       3 08:16:58

The first thing to do is check the status of your job with lpq. This will show the current jobs in the queue and lpd server. The Server value is the process that is responsible for sending jobs to the printer. It starts the Unspooler process that does the actual transfer to the remote system. Each time a job is processed a new Unspooler process is created. The Server process stays active until there is no further work to be done for the print queue.

Figure 2-16. Using the lpq -l Option

    h110: {2} % lpq -l
    Printer: lp@h110
     Queue: 1 printable job
     Server: pid 8741 active
     Unspooler: pid 8742 active
     Status: printing job 'papowell@h110+740' at 08:16:58.465
     Status: processing 'dfA740h110.private', size 3, format 'f',
         IF filter 'ifhp' at 08:16:58.465
     Filter_status: getting end using 'pjl job/eoj' at 08:16:59.902
     Filter_status: code = 10003, 'Warming Up' at 08:17:02.045
     Rank   Owner/ID          Class Job Files      Size Time
    active papowell@h110+740  A     740 /tmp/hi       3 08:16:58
    h110: {3} % lpq -lll
    Printer: lp@h110
     Queue: 1 printable job
     Server: pid 8741 active
     Unspooler: pid 8742 active
     Status: accounting at start at 08:16:58.455
     Status: opening device 'h14%9100' at 08:16:58.455
     Status: printing job 'papowell@h110+740' at 08:16:58.465
     Status: processing 'dfA740h110.private', size 3, format 'f',
         IF filter 'ifhp' at 08:16:58.465
     Filter_status: data sent at 08:16:59.902
     Filter_status: sent job file at 08:16:59.902
     Filter_status: getting end using 'pjl job/eoj' at 08:16:59.902
     Filter_status: code = 10003, 'Warming Up' at 08:17:02.045
     Rank   Owner/ID          Class Job Files      Size Time
    active papowell@h110+740  A     740 /tmp/hi       3 08:16:58

The lpq -l (longer) option increases the number of Status and Filter_status lines shown. These lines come from the status.%P and status files in the spool queue. Adding more -l options increases the amount of status shown.

Figure 2-17. Using the lpq -L Option

    
    h110: {4} % lpq -L
    Printer: lp@h110
     Queue: 1 printable job
     Server: pid 8741 active
     Unspooler: pid 8742 active
     Status: waiting for subserver to exit at 08:16:58.451
     Status: subserver pid 8742 starting at 08:16:58.455
     Status: accounting at start at 08:16:58.455
     Status: opening device 'h14%9100' at 08:16:58.455
     Status: printing job 'papowell@h110+740' at 08:16:58.465
     Status: processing 'dfA740h110.private', size 3, format 'f',
         IF filter 'ifhp' at 08:16:58.465
     .....
    
     Filter_status: decoded job type 'PCL' at 08:16:59.901
     Filter_status: job type 'PCL' at 08:16:59.901
     Filter_status: transferring 3 bytes at 08:16:59.902
     Filter_status: 100 percent done at 08:16:59.902
     Filter_status: data sent at 08:16:59.902
     Filter_status: sent job file at 08:16:59.902
     Filter_status: getting end using 'pjl job/eoj' at 08:16:59.902
     Filter_status: code = 10003, 'Warming Up' at 08:17:02.045
     .....
    
     Rank   Owner/ID          Class Job Files     Size Time
    active papowell@h110+740    A   740 /tmp/hi      3 08:16:58

If you want to see LOTS of status, use lpq -L, which shows all the avilable status information.

Figure 2-18. Job Completion

    h110: {5} % lpq
    Printer: lp@h110
     Queue: no printable jobs in queue
     Status: job 'cfA740h110.private' removed at 08:18:07.776
     Filter_status: done at 08:18:07.756
    h110: {6} % lpq -lll
    Printer: lp@h110
     Queue: no printable jobs in queue
     Status: printing job 'papowell@h110+740' at 08:16:58.465
     Status: processing 'dfA740h110.private', size 3, format 'f',
         IF filter 'ifhp' at 08:16:58.465
     Status: IF filter 'ifhp' filter finished at 08:18:07.757
     Status: printing finished at 08:18:07.757
     Status: accounting at end at 08:18:07.774
     Status: finished 'papowell@h110+740', status 'JSUCC' at 08:18:07.774
     Status: subserver pid 8742 exit status 'JSUCC' at 08:18:07.775
     Status: lp@h110.private: job 'cfA740h110.private' printed at 08:18:07.775
     Status: job 'cfA740h110.private' removed at 08:18:07.776
     Filter_status: transferring 3 bytes at 08:16:59.902
     Filter_status: 100 percent done at 08:16:59.902
     Filter_status: data sent at 08:16:59.902
     Filter_status: sent job file at 08:16:59.902
     Filter_status: getting end using 'pjl job/eoj' at 08:16:59.902
     Filter_status: code = 10003, 'Warming Up' at 08:17:02.045
     Filter_status: end of job detected at 08:18:06.457
     Filter_status: pagecounter 105341 after 1 attempts at 08:18:07.756
     Filter_status: pagecounter 105341, pages 1 at 08:18:07.756
     Filter_status: done at 08:18:07.756

When your job is finished, you can use the lpq -lll options to see the final results of processing the job.

Figure 2-19. Summary Status Displays

    h110: {7} % lpq -s
    lp@h110 0 jobs
    h110: {239} % lpq -s -a
    lp@h110 0 jobs
    lp0@h110 0 jobs (printing disabled)
    h110: {8} % lpc status
     Printer    Printing Spooling Jobs  Server Subserver Redirect Status/(Debug)
    lp@h110      enabled  enabled    0    none    none
    h110: {9} % lpc status all
     Printer    Printing Spooling Jobs  Server Subserver Redirect Status/(Debug)
    lp@h110      enabled  enabled    0    none    none
    lp0@h110    disabled  enabled    0    none    none
    h110: {10} % exit

The lpq -s (short status) shows a single summary line for status. Adding the -a (all queues) will print information for all the print queues.

The lpc status command queries the lpd server and reports the status of the queues operated by the lpd server. The lpd status all will show the status of all the print queues.


2.4. Diagnostics for lpd Problems

Figure 2-20. lpd Options

    h110# lpd -=
    lpd: Illegal option '='
    usage: lpd [-FV] [-D dbg] [-L log]
     Options
     -D dbg      - set debug level and flags
                     Example: -D10,remote=5
                     set debug level to 10, remote flag = 5
     -F          - run in foreground, log to STDERR
                   Example: -D10,remote=5
     -L logfile  - append log information to logfile
     -V          - show version info
    h110# lpd -D=
    debug usage: -D [ num | flag=num | flag=str | flag | flag@ | flag+N ]*
      flags recognized: network[+N,@], database[+N,@], lpr[+N,@],
       lpc[+N,@], lprm[+N,@], lpq[+N,@], log[+N,@],
       test=num

The lpd server can be started in debug mode. However, the amount of information produced can be overwhelming. If you need to determine what is happening during initial connection, then you will have to do this.

Figure 2-21. Using lpd Debug Options

    h110# lpd
    h110# lpd -F -D1
    2001-10-18-05:56:55 [8156] lpd  Initialize: starting
    ...
    2001-10-18-05:56:55.228 h110 [8156] lpd  lpd: listening socket fd -6
    Fatal error - Another print spooler is using TCP printer
        port, possibly lpd process '8154'
    2001-10-18-05:56:55.228 h110 [8156] lpd  cleanup: done, exit(1)
    h110# killall lpd
    h110# lpd -F -D1
    2001-10-18-05:57:05 [8158] lpd  Initialize: starting
    ...
    2001-10-18-05:57:05.800 h110 [8159] Waiting  lpd: LOOP START
    2001-10-18-05:57:05.800 h110 [8159] Waiting
          lpd: starting select timeout 'yes', 600 sec, max_socks 7
    
    ---- other window
         h110: {5} % lpr /tmp/hi
    ----
    
    2001-10-18-05:57:44.341 h110 [8159] Waiting
         lpd: select returned 1, error 'No Error'
    2001-10-18-05:57:44.342 h110 [8159] Waiting
         lpd: fd 5 readable
    2001-10-18-05:57:44.342 h110 [8159] Waiting  lpd: connection fd 8
    2001-10-18-05:57:44.351 h110 [8159] Waiting  Start_worker: fd 8
    
    2001-10-18-05:57:44.356 h110 [8171] RECV  lp: Fix_Rm_Rp_info: printer name 'lp'
    2001-10-18-05:57:44.356 h110 [8171] RECV  Reset_config: starting
    2001-10-18-05:57:44.361 h110 [8171] RECV
         lp: Select_pc_info: looking for 'lp', depth 0
    ...

This shows all of the information available about the printing operation. But it is jumbled all together. Usually you want to see just the information about a single spool queue.

Figure 2-22. Debugging Spool Queue

    Printcap:
      lp:sd=/var/spool/lpd/%P
        :db=DebugOptions
           db=1     - output to device level 1,
           db=lpc db=lpq db=lpr db=lprm
                    - incoming lpc, lpq, lpr, lprm operations
    
    Spool Queue:  /var/spool/lpd/lp
      Default Files - created by checkpc
        control.%P  - queue control (enable, disable...)
        acct        - accounting
        status      - filter status
        status.%P   - queue status
        log         - diagnostics

The checkpc program creates a standard set of files in each spool queue, including the log file. The :db=DebugOptions enables debugging output for the specified operation. Information is sent to the log file as soon as the print queue directory and debug flags for the spool queue are determined.

Figure 2-23. Setting Queue Debug Options

    h110# vi /etc/printcap
      set:
        lp:...
          :db=lpr
    h110# lpc reread
    lpd server pid 8200 on h110.private, sending SIGHUP

Edit the printcap. You can then use lpc reread to signal the lpd process to read the new /etc/printcap file.

Figure 2-24. log File

    2001-10-18-06:11:30.349 h110 [8216] RECV
       lp: Receive_job: debug 'lpr', Debug 0, DbgFlag 0x1000
    2001-10-18-06:11:30.349 h110 [8216] RECV
       lp: Receive_job: spooling_disabled 0
    2001-10-18-06:11:30.349 h110 [8216] RECV
       lp: Receive_job: sending 0 ACK for job transfer request
    2001-10-18-06:11:30.349 h110 [8216] RECV
       lp: Receive_job: from localhost.my.domain- getting file transfer line
    2001-10-18-06:11:30.349 h110 [8216] RECV
       lp: Receive_job: read from localhost.my.domain-
           status 0 read 23 bytes '^B131 cfA215h110.private'

You can now use the log file to see the individual queue operations. The size of the log file is determined by the max_log_file_size (default is 1000Kbytes); when the log file exceeds this it is truncted to 25% of its maximum length.


Chapter 3. Printers

Figure 3-1. Printer Types

    Printers:
      Cheap and Slow Ink Dispensers
      Not So Cheap Fast Printers
      Vintage Stuff On Sale
      Legacy Junk You Are Stuck With

Your office mate has just purchased a nice new $99 ink-jet printer and wants to use it on his office desktop. Your boss calls you in and tells you that the new PlattenPusher 5500 printer will arrive and it needs to be operational ASAP. And finally, you pick up a really good bargin on a used HP4mPlus laser printer, which all the folks on the LPRng mailing list recommend as the most reliable (and SLOW...) printer they ever used.

With your luck, probably all three happen on the same day. Welcome to the wonderful world of printers.


3.1. Interface

Figure 3-2. Interface Types

    Connection:
      Parallel port : write only (no status)
                      read/write (maybe you get status)
      Serial port:    read/write (status)
      Network:        serial port emulator
                      parallel port emulator
                      print spooler emulator
                      whacko interface

The type of interface on your printer is usually a function of the printer cost and speed. The low cost/low speed printers usually have a parallel port interface, while the higher cost/higher speed printers usually have both a parallel port and a network interface. Serial ports are usually found only on older model printers or those which have very special facilities.


3.2. Parallel Port

Figure 3-3. Parallel Port

Some printers provide status information. In order to do this they need a bidirectional communications channel. The parallel port interface found on the original X86 PC/XT/ATX systems was write only. However, there were a couple of signals (OUT OF PAPER, ERROR, etc.) that provided status information to the computer system. By monitoring these signals the host computer could tell the user that there were problems with the printer. Fiendishly clever engineers discovered that they could use these signals to implement a bidirectional data channel over the parallel port. They could even put multiple devices (daisy chained) on the parallel port. Needless to say, of the hundreds of companies that used bidirectional parallel interfaces no two of them used the same method.

In a fit of desperation, the IEEE1284 standard (well, actually 3 standards) were developed to allow at least some sort of general consensus on how a bidirectional parallel port should work.

If you are interested in the details about Parallel Ports, see http://www.fapo.com/1284int.htm for a nice introduction, and the IEEE1394 Trade Association Home Page http://www.1394ta.com/ for pointers to other information.

The good news is that if your printer is IEEE1284 compliant, then it has a functional bidirectional interface that will return status and other information. The bad news, really bad news, and really really bad news is a) there is no software level API for using bidirectionality; b) the parallel IO drivers that exist differ from version to version; c) most of the time the status returned by the printer is useless anyways.

Given this set of problems I recommend that you:

  • Put only one device (your printer) on each parallel port.

  • Do not expect to get status information back from the printer.

Figure 3-4. Parallel Port Printcap

    lp:lp=/dev/lpt0
      :sd=/var/spool/lpd/%P


As shown in Figure 1-1, the printcap entry for a parallel port (without a filter) is really simple. If your printer is offline or powered down, lpd will not be able to open the parallel port and you will see an endless list of error messages in the status file.

Figure 3-5. Loading Linux Parallel Port Driver

    [papowell@h112 papowell]$ su
    Password:
    [root@h112 papowell]# echo </dev/lp0
    [root@h112 papowell]# cd /proc/sys/dev/parport/
    [root@h112 parport]# ls default  parport0
    [root@h112 parport]# cd parport0
    [root@h112 parport0]# ls autoprobe  autoprobe0  autoprobe1  autoprobe2
       autoprobe3  base-addr  devices  dma  irq  modes  spintime
    [root@h112 parport0]# cat autoprobe
    CLASS:PRINTER; MODEL:DESKJET 670C;
    MANUFACTURER:HEWLETT-PACKARD;
    DESCRIPTION:Hewlett-Packard DeskJet 670C;
    COMMAND SET:MLC,PCL,PML;

The Linux system uses loadable module drivers for the parallel ports and newer releases support the IEEE1284 device probe functions. You can use the command shown in Figure 3-5 to load the modules; the echo </dev/lp0 command tries to open the device in read mode, and then exits after reading nothing... which might suggest that you cannot get status from the device. If you have the /proc system installed, then you can see what the IEEE1284 probe function returned.

Figure 3-6. Parallel Port Problems

    One Interrupt per Output Character
       - One Interrupt per Blocks of Characters (DMA)
       - Hope that DMA works
    May operate by polling
    Don't try to daisy chain devices

While you may think that you are getting a high throughput to the parallel port, in actual fact it may be very slow. In the worst case you will get a an interrupt for every character output. Even worse, sometimes the parallel port driver will spin block for a small period of time in the hopes that a character will be accepted by the printer so it can send another one. Finally, while many users have successfully daisy chained multiple devices, there is a resounding silence from them when asked about the success of simultaneous use of the devices.

To add insult to injury, some systems do not even support interrupts with their parallel port hardware. To do IO, they periodically poll the output device to see if it is ready to accept another character.


3.3. Network Ports

Figure 3-7. Network Ports

Most devices that support a network connection do so by either providing support for a print spooler interface (lpd) or by emulating a bidirectional connection to the printing device (socket or appsocket). If your printer provides status reporting, it is strongly recommended that you use the socket interface. This will allow you to monitor conditions reported by the printer.

Figure 3-8. Network Port Printcap

    lp:lp=10.0.0.14%9100
      :sd=/var/spool/lpd/%P
    
    lp2:lp=raw@10.0.0.14
      :sd=/var/spool/lpd/%P
      # legacy :rp:rm support
      # :rp=raw:rm=10.0.0.14

The printcap for a network printer is shown in Figure 3-8. You can use the :rp:rm options if you want.

Figure 3-9. Benefits of Network Port Printcap

    High Speed
    Low Error Rate (+ Error Detection)
    Long Distances
    Very low system overhead

Network port printing is effectively the highest speed. The TCP/IP protocol provides both flow control and error detection/correction. The printer and host system can be separated by quite large distances. Finally, the overhead of the TCP/IP connection is very low in terms of hardware and software.

Figure 3-10. Network Print Server

If you have legacy systems that have serial or parallel ports, you can buy a Network Print Server box. These have a network interface and one or more parallel or serial port interfaces.

Table 3-1. Network Print Server Configuration Information

Manufacturer Model RFC1179 Port Name (rp=XXX) Send to TCP port
Cannon Printer Cannon 460 PS, no hard drive xjdirect - Unknown if supported -
  Cannon 460 PS hard drive xjprint - print immediately,xjhold - print later - Unknown if supported -
Digital Products Inc. NETPrint Print Server PORTn, where n is port on server - Unknown if supported -
Electronics For Imaging Inc. Fiery RIP i series normalq or urgentq - Unknown if supported -
  Fiery RIP XJ series xjprint - Unknown if supported -
  Fiery RIP XJ+ and SI series print_Model, e.g. print_DocuColor - Unknown if supported -
  Fiery models ZX2100, ZX3300, X2, X2e print - Unknown if supported -
Emulex Corp. NETJet/NETQue print server PASSTHRU - Unknown if supported -
Extended Systems Inc. ExtendNet Print Server Printern, where n is port on server - Unknown if supported -
Hewlett-Packard JetDirect interface card raw 9100
Hewlett-Packard JetDirect Multiport Server port 1 - raw1, port 2 - raw2, etc. port 1 - 9100, port 2 - 9101, etc.
I-Data Easycom 10 Printserver par1 (parallel port 1) - Unknown if supported -
  Easycom 100 Printserver LPDPRT1 - Unknown if supported -
IBM Network Printer 12, 17, 24, and 24PS PASS - Unknown if supported -
Lantronix EPS1, EPS2 EPS_X_S1 (serial) port 1, EPS_X_P1 (parallel) port 2, etc. 3001 (port 1), 3002 (port 2), etc.
QMS Various Models RAW 35 (AppSocket)
Tektronix Tektronix printer network cards PS (PostScript), PCL (PCL), or AUTO(Auto-selection between PS, PCL, or HPGL). Not reliable. 9100 (AppSocket on some models)
Rose Electronics Microserve Print Servers lp 9100
Xerox Models 4505, 4510, 4517, 4520 PASSTHRU 2501 (AppSocket on some models)
  Model 4512 PORT1 10001 (programmable)
  Model N17 RAW 9100
  Models N24 and N32 RAW 2000
  Models 4900, 4915, 4925, C55 PS 2000
  Document Centre DC220/230 lp - Unknown if supported -

All company, brand, and product names are properties of their respective owners.


3.4. Sending To SMB (Samba, Microsoft) Printer, Novell, Appletalk

Figure 3-11. Using Program To Send To Printer

There are a wide number of other print spooling systems that have been developed over the years. Most of these use proprietary or arcane protocols to transfer files. These include the SMB protocol used by Microsoft, the Novell print spooler support, and the Apple corporation Appletalk (Copyright, Trademarks where applicable). These systems usually run on or with non-UNIX Operating Systems or on proprietary hardware. But over the years packages have been developed to interface to these systems.

Figure 3-12. Protocols, Packages, and Transfer Programs

    Protocol        Package       Transfer Program
    SMB (CIFS)      Samba         smbclient + wrapper
       WWW: http://www.samba.org
    Novell Netware  ncpfs (Linux) nprint + wrapper
       FTP: ftp.gwdg.de/pub/linux/misc/ncpfs
       (Also Linux Kernel Documentation/filesystems)
    Appletalk       CAPS          pap + wrapper
       WWW: http://sourceforge.net/projects/netatalk
       WWW: http://www.umich.edu/~rsug/netatalk

Each of these programs will transfer a print job to a remote system.

Figure 3-13. Printcap For Transfer Programs

    lp:
      OR
      :lp=|/usr/local/lib/filters/smbprint
      OR
      :lp=|/usr/local/lib/filters/ncpprint
      OR
      :lp=|/usr/local/lib/filters/atalkprint
      # and the magic happens here
      :options=authfile="auth" host="h114" printer="lp" workgroup="ASTART"
      # See the LPRng/UTILS directory

You can specify a program to do the transfer to the remote host. The program will connect to the remote system and transfer STDIN to the printer. Errors will be written to STDERR and be put in the log by LPRng.

Figure 3-14. Samba smbclient Wrapper

    #!/bin/sh
    # configuration
    smbclient=/usr/local/bin/smbclient
    
    # get options from $PRINTCAP_ENTRY environment variable
    PATH=/bin:/usr/bin:/usr/local/bin
    options=`echo "${PRINTCAP_ENTRY}" | sed -n 's/:options=//p' `
    echo OPTIONS $options >&2
    if [ -n "$options" ] ; then
        # paranoia:  $options=`echo |perl -sp 's/[^\w\s,-+%="\']/ /'`
        eval dummy=v `echo $options`;
    fi
    
    if [ "$oldversion" != "" -a "$authfile" != "" -a -f "$authfile" ] ; then
        . $authfile;
        $authfile=
    fi
    
    if [ "$translate" = "yes" ]; then
     command="translate ; print -"
    else
     command="print -"
    fi
    
    echo $smbclient "$share" ${password:+password} -E \
     ${username:+-U} ${username:+username} ${hostip:+-I} \
     $hostip -N ${workgroup:+-W} $workgroup \
     ${authfile:+-A} $authfile -c "$command" >&2
    $smbclient "$share" ${password} -E \
     ${username:+-U} ${username} ${hostip:+-I} \
     $hostip -N ${workgroup:+-W} $workgroup \
     ${authfile:+-A} $authfile -c "$command" >&2

The smbprint script is run with the $PRINTCAP_ENTRY environment variable set to the printcap (See Figure 3-15). The value is scanned for the :options line and then this line is used with eval to set variables. This is a slight security risk and you should not have any metacharacters in the options field, so you can optionally strain them out or you can trust in your editting skills in the printcap.

Figure 3-15. $PRINTCAP_ENTRY

    lp:
      :lp=|/usr/local/lib/filters/smbprint
      :options=authfile="auth" host="h114" printer="lp" workgroup="ASTART"

There older versions of the smbclient required the user name and password on the command line. Unfortunately, the ps command would show the command line options, allowing users to see the password. Newer versions can read username and password from an authentication file. We can use either version by setting the oldversion option.

Finally, we echo the command for logging purposes (note that $password is not displayed and then run the smbclient command.

Figure 3-16. Novell and Appletalk Wrappers

    ncpprint:
     ....
     usercmd=""
     if [ "$username" != "" ]; then
       if [ "$password" != "" ]; then
         usercmd="-U $username -P $password"
       else
         usercmd="-U $username -n"
       fi
     fi
     nprint=/usr/bin/nprint -S $server -q $printer \
        $usercmd -N - 2>/dev/null
    
    atalkprint:
     ...
     /usr/bin/pap -p "$username:$printer@$host"

This general template can also be used with the nprint command from the Novell Netware support package to send files to a Novel Netware printers and the pap command from the Netatalk package.


3.5. Serial Port

Figure 3-17. Serial Port

A serial line is usually bidirectional in operation, but there are very few printers that will return status information. The most notable exception to this are PostScript printers. If you use a serial port printer, it is absolutely essential that you implement flow control, and almost mandatory that you use hardware or RTS-CTS (Request To Send and Clear To Send) flow control. Finally, you need to have the serial line operate in RAW mode, so that the serial line driver does not abuse the output stream by introducing extraneous CR-LF sequences, and changing control characters such as ESC (Escape) into ^E sequences.

Figure 3-18. Serial Port Printcap

    lp:lp=/dev/tty00
      :stty=raw crtscts 19200
      :sd=/var/spool/lpd/%P
      # optional Open Read Write
      #:rw

The :stty=... option is used to set line characteristics and takes a subset of the stty application parameters. You need to set the line speed and mode. If you need to get status information back from the printer, you should add the :rw (Open Read-Write) flag.

As you might suspect, the serial port is limited by the line speed. In addition, it has a higher rate of errors than you might expect. Most printers that use a serial port are for legacy purposes or have low speed and low data transfer requirements.


Chapter 4. Printer Job Formats

Figure 4-1. Page Description Lanaguages

    Printer Input File Formats:
    
      Postscript (Level 1, 2, 3)
      PCL (PCL 5)
      Text (Really Legacy PCL)
    
      PJL
        Configuration Specification for Job
         - PostScript or PCL or HPGL or ...
    
      Magic Mystery Proprietary Format

Most printers will only print jobs that have a particular format. These formats are called Page Description Languages. The most common are PostScript, PCL, and HPGL.

Figure 4-2. How To Identify Print Formats

    Print Job Job Types
       Start of File           File Type
    
       %!                      PostScript - Level Unknown
       %!PS-Adobe-1.0          PostScript - Level 1.0
       %!PS-Adobe-2.0          PostScript - Level 2.0
       %!PS-Adobe-2.1          PostScript - Level 2.0
       %!PS-Adobe-3.0          PostScript - Level 2.0
       \033%-12345X@PJL        HP Printer Job Language data
       \033E\033               HP PCL printer data
       This ...                Text

The type of file can be identified by looking at the content near the start of the file. This is how the file program determines the type of file Figure 1-1.

Figure 4-3. Using the file Application

    h110: {1} % file *
    Makefile:          ASCII English text
    atalkprint:        Bourne shell script text executable
    logo.gif:          GIF image data, version 89a, 250 x 91,
    one.pcl:           HP PCL printer data
    one.ps:            PostScript document text conforming at level 3.0
    one.pjl:           HP Printer Job Language data
    rewindstdin:       ELF 32-bit LSB executable
    testpage-a4.fig:   FIG image text, version 3.1
    testpage-a4.ps:    PostScript document text conforming at level 2.0
    testpage.fig:      FIG image text, version 3.1

4.1. PostScript

Figure 4-4. One PostScript Page

    %!PS-Adobe-3.0
    %% one page (i.e. - a page with a 1 on it)
    %%/Times-Roman
    /Courier
    findfont 200 scalefont setfont
    72 300 moveto
    (1) show
    showpage
    
    
     -- from PostScript Reference Manual 1986
        Adobe (www.adobe.com)

This is an example of a PostScript File.

Figure 4-5. Generate One Page

    h110: {1} % echo 1 |groff -Tps >/tmp/one.ps
    h110: {2} % more /tmp/one.ps
    %!PS-Adobe-3.0
    %%Creator: groff version 1.16.1
    %%CreationDate: Thu Oct 18 12:48:45 2001
    %%DocumentNeededResources: font Times-Roman
    %%DocumentSuppliedResources: procset grops 1.16 1
    %%Pages: 1
    %%PageOrder: Ascend
    %%Orientation: Portrait
    %%EndComments
    %%BeginProlog
    %%BeginResource: procset grops 1.16 1
    /setpacking where{
    pop
    currentpacking
    true setpacking
    }if
    /grops 120 dict dup begin
    /SC 32 def
    /A/show load def
    /B{0 SC 3 -1 roll widthshow}bind def

The quick way to generate a test page is use groff. The groff -Tps outputs PostScript.

Figure 4-6. PostScript Document Structuring Conventions

    Specifies how a PostScript print job should be formatted
    Divides the job up into a  prolog and body
    The body contains pages
       - each page is in an individual section
       - each page is independant
    
    Various Levels - 3.0 with PostScript Level 3, etc.

Most document generation systems produce PostScript that meets the PostScript Document Structuring Convention. This allows you to massage PostScript Documents in several ways.

Figure 4-7. Tools for PostScript Document Manipulation

    GhostScript - format conversion
       WWW: http://www.ghostscript.com
    PSUtils  - utilities to massage PostScript by Angus Duggan
       FTP: ftp://ftp.dcs.ed.ac.uk/pub/ajcd/
       WWW: http://www.dcs.ed.ac.uk/home/ajcd/psutils/
    psbook            rearranges pages into signatures
    psselect          selects pages and page ranges
    pstops            performs general page rearrangement and selection
    psnup             put multiple pages per physical sheet of paper
    psresize          alter document paper size
    epsffit           fits an EPSF file to a given bounding box
    getafm     (sh)   outputs PostScript to retrieve AFM file from printer
    showchar   (sh)   outputs PostScript to draw a character with metric info
    fixdlsrps  (perl) filter to fix DviLaser/PS output so that PSUtils works
    fixfmps    (perl) filter to fix framemaker documents so that psselect etc. work
    fixmacps   (perl) filter to fix Macintosh documents with saner version of md
    fixpsditps (perl) filter to fix Transcript psdit documents to work with PSUtils
    fixpspps   (perl) filter to fix PSPrint PostScript so that psselect etc. work
    fixscribeps (perl) filter to fix Scribe PostScript so that psselect etc. work
    fixtpps    (perl) filter to fix Troff Tpscript documents
    fixwfwps   (perl) filter to fix Word for Windows documents for PSUtils
    fixwpps    (perl) filter to fix WordPerfect documents for PSUtils
    fixwwps    (perl) filter to fix Windows Write documents for PSUtils
    extractres (perl) filter to extract resources from PostScript files
    includeres (perl) filter to include resources into PostScript files
    psmerge    (perl) hack script to merge multiple PostScript files


The combination of GhostScript and PSutils by Angus Duggan are a powerful combination.

Figure 4-8. Selection of Pages + 4up Printing

    h110: {81} % psselect -p20-24 LPRng-HOWTO.ps | psnup -4 >p4up.ps
    [20] [21] [22] [23] [24] Wrote 5 pages, 38404 bytes
    [1] [2] Wrote 2 pages, 42769 bytes

Figure 4-9. PostScript Output

Figure 4-10. End Of PostScript Job: ^D (CTRL-D)

    ^D is recognized as an 'end of job'
       - causes reset of PostScript interpreter to defaults
    
    ^D%!PS-Adobe-3.0
    ...
    ^D
    
    The Dreaded ^D at Start of Job - causes problems
      Rest of job may be ignored!
      Solution: strip off ^D at start
        (ifhp = ps_eoj_at_start@)
    
    The Dreaded ^D at End of Job - causes problems when
      you are trying to massage postscript or append jobs
      Solution: strip off ^D everywhere
        (ifhp = ps_eoj_at_end@)

The ^D (CTRL-D) character is evil - it usually should not be put into raw files.


4.2. PCL

Figure 4-11. One PCL Page

    ^[E^[&u600D^[&l2A^[&l0O^[&l0E^[(0N^[(s1p0s0b4101T
      ^[(s24V^[*p655x942Y1^L^[E
    
    Note: ^[ is ESC or \033
          ^[E is 'reset printer configuration'

This is an example of a PCL file. Note that the file starts with ^[E, or the reset configuration string. All PCL jobs should start with this so that the previous job does not cause a problem.

Figure 4-12. Generate One Page

    h110: {1} % echo 1 | groff -Tlj4 >/tmp/one.pcl
    h110: {2} % more
    ^[E^[&u600D^[&l2A^[&l0O^[&l0E^[(0N^[(s1p0s0b4101T
      ^[(s24V^[*p655x942Y1^L^[E

The quick way to generate a test page is use groff. The groff -Tlj4 outputs PCL level 5. Again, watch out for the evil ^D (CTRL-D) characters.


4.3. Printer Job Language (PJL) and PostScript, PCL

Figure 4-13. PJL Example

    ^[%-12345X@PJL
    @PJL RDYMSG DISPLAY = ":"
    @PJL USTATUSOFF
    @PJL USTATUS JOB = ON
    @PJL USTATUS DEVICE = ON
    @PJL USTATUS PAGE = ON
    @PJL USTATUS TIMED = 10
    @PJL ENTER LANGUAGE = POSTSCRIPT
    ^D%!
    %!PS-Adobe-3.0
    %% one page (i.e. - a page with a 1 on it)
    %%/Times-Roman
    /Courier
    findfont 200 scalefont setfont
    72 300 moveto
    (1) show
    showpage
    ^D^[%-12345X@PJL
    @PJL RDYMSG DISPLAY = ":"
    @PJL EOJ NAME = ":"
    @PJL USTATUSOFF
    @PJL USTATUS JOB = ON
    @PJL USTATUS DEVICE = ON
    @PJL USTATUS PAGE = ON
    @PJL USTATUS TIMED = 10
    @PJL RDYMSG DISPLAY = "Done: :"
    ^[%-12345X

Printer Job Language is used to set up configuration and other facilities for a printer. It can establish defaults for printing and provide direction to the printer on how to handle job items not specified by the PostScript or PCL language.

The PJL Reset command ^[%-12345X performs a Print Job lanaguage independent reset. This allows PJL to be used with PostScript or PCL.


4.4. Text Files

Figure 4-14. Text Files and The Jaggies

    Text
      - usually ASCII characters
    
    The Dreaded Jaggies
    
    File:
    
       This is what you
       see on the printer
    
    Printer output:
    
       This is what you
                       see on the printer

Text is usually just ASCII characters. Unix lines are terminated with new line (NL or \012, and when sent to a printer result in The Jaggies. You need to have carriage returns (CR or \015 added to the file. You need to fix this by one of several methods.

Figure 4-15. Fixing The Jaggies

    Fixing The Jaggies:
     Convert NL to CR/NL
       Quick and Dirty
         sed -e 's/$/\r/'
       OR
         lpf (LPRng utility)
    
     Make PCL Printer Interpret CR as CR/LF
       ^[E  ->  ^[E&k2G
       Remove the PCL Reset and add the &k2G
        (CR -> CR/LF command)

4.5. Magical Mystery Proprietary Format

Figure 4-16. Magical Mystery Formats

    Magical Mystery Proprietary Format
      -  Usually a RASTER format
    
      -  legacy devices such as Versatek Plotters
    
      -  new super cheap InkJet Printers
         The host system needs to do conversion to raster file
      -  Dirty Little Secret - some of these understand PCL Level 5
         (monochrome) and are compatible with HP LaserJet 4.

You should try and see if your printer understands PCL. Try using GhostScript with the hpdj, ljet3 or ljet4.

Figure 4-17. GhostScript To The Rescue

    h110: {64} % gs --help
    AFPL Ghostscript 6.50 (2000-12-02)
    Copyright (C) 2000 Aladdin Enterprises, Menlo Park, CA.  All rights reserved.
    Usage: gs [switches] [file1.ps file2.ps ...]
    Most frequently used switches: (you can use # in place of =)
     -dNOPAUSE           no pause after page   | -q       `quiet', fewer messages
     -g<width>x<height>  page size in pixels   | -r<res>  pixels/inch resolution
     -sDEVICE=<devname>  select device         | -dBATCH  exit after last file
     -sOutputFile=<file> select output file: - for stdout, |command for pipe,
                                             embed %d or %ld for page #
    Input formats: PostScript PostScriptLevel1 PostScriptLevel2 PDF

You can read PostScript level 1, 2, or PDF with this version of GhostScript.

Figure 4-18. GhostScript Devices

    Available devices:
       x11 bbox x11alpha x11cmyk x11cmyk2 x11cmyk4 x11cmyk8 x11gray2 x11gray4
       x11mono x11rg16x x11rg32x atx23 atx24 atx38 deskjet djet500 fs600
       laserjet ljetplus ljet2p ljet3 ljet3d ljet4 ljet4d lp2563 oce9050 lj5mono
       lj5gray epswrite pswrite pdfwrite pxlmono pxlcolor bit bitrgb bitcmyk
       bmpmono bmpgray bmpsep1 bmpsep8 bmp16 bmp256 bmp16m bmp32b cgmmono cgm8
       cgm24 jpeg jpeggray miff24 pcxmono pcxgray pcx16 pcx256 pcx24b pcxcmyk
       pcx2up pbm pbmraw pgm pgmraw pgnm pgnmraw ppm ppmraw pnm pnmraw pkm
       pkmraw pksm pksmraw plan9bm pngmono pnggray png16 png256 png16m psmono
       psgray psrgb faxg3 faxg32d faxg4 tiffcrle tiffg3 tiffg32d tiffg4 tifflzw
       tiffpack tiff12nc tiff24nc appledmp iwhi iwlo iwlq bj10e bj200 ccr
       cdeskjet cdjcolor cdjmono cdj500 cdj550 declj250 dnj650c lj4dith pj pjxl
       pjxl300 bjc600 bjc800 escp djet500c cljet5 cljet5pr cljet5c lj3100sw
       coslw2p coslwxl cp50 epson eps9mid eps9high ibmpro epsonc ap3250 st800
       stcolor uniprint lj250 paintjet pjetxl hl7x0 imagen jetp3852 lbp8 lips3
       lp8000 m8510 necp6 lq850 lxm5700m oki182 okiibm photoex sj48 t4693d2
       t4693d4 t4693d8 tek4696 cfax dfaxlow dfaxhigh cif inferno mgrmono
       mgrgray2 mgrgray4 mgrgray8 mgr4 mgr8 sgirgb sunhmono cdj850 hpdj pcl3
       hpdjplus hpdjportable hpdj310 hpdj320 hpdj340 hpdj400 hpdj500 hpdj500c
       hpdj510 hpdj520 hpdj540 hpdj550c hpdj560c hpdj600 hpdj660c hpdj670c
       hpdj680c hpdj690c hpdj850c hpdj855c hpdj870c hpdj890c hpdj1120c cdj970
       stp nullpage

GhostScript converts PostScript to a wide range of output device formats. The interesting ones are ljet4, lj5mono, hpdj, and so forth. These are Ink Jet printers with various strange behaviors.

The http://www.ghostscript.com site has links to just about everything concerned with GhostScript. the http://www.cs.wisc.edu/~ghost site mirrors much of this information. The printer.htm and devices.htm are good sources for information about printing.


4.6. Printing Test Pages

Figure 4-20. Printing Test Pages To Parallel Port

    #!/bin/sh
    for i in one.pcl one.pjl one.ps ; do
     cat $i >/dev/lp0
    done

The easiest way to print the test pages is to try them all. This is brutal, but you may need to do it at least once.

Figure 4-21. Using Netcat (nc)

    nc -  Netcat by Mudge
    http://www.avian.org/
    ftp://ftp.lprng.com/pub/LPRng/TOOLS/netcat
    #!/bin/sh
    for i in one.pcl one.pjl one.ps ; do
     nc -w10 10.0.0.14 9100  <$i
    done
    
    h110: {453} % sh -x /tmp/testnc
    + nc -w10 -v -v 10.0.0.14 9100
    h14.private [10.0.0.14] 9100 (jetdirect) open
    @PJL USTATUS DEVICE
    CODE=10003
    DISPLAY="02 WARMING UP"
    ONLINE=TRUE
    
    ...
    @PJL USTATUS TIMED
    CODE=10001
    DISPLAY="Done: papowell /"
    ONLINE=TRUE
    
    ^C

Netcat is a handy tool for testing network connections to a printer. You can also use it as a port mapper and find out what interesting ports are open on your print spooler box.


Chapter 5. Filters

Figure 5-1. Filters

A filter is responsible for converting the job data files to a format compatible with the printer, transfering the job to the printer, and monitoring for any problems.

Figure 5-2. Filter Specification in Printcap Entry

    # LPRng
    lp:
      :filter=/.../filter
    
    # Legacy BSD (LPRng is backwards compatible)
    lp:
      # file 'format' is lower case letter X, filter is
      # 'Xf' option value, default format is 'f' so default
      # filter is 'if'
      :if=/.../filter
      :hf=/.../filter

The legacy BSD printing system required you to specify a filter for all input types. LPRng uses :filter to specify a default filter. Much more in line with modern printing.

Figure 5-3. Specifying Job Datafile Format

    LPRng 'format' selection:
    
       h110: {295} % lpr -Fx /tmp/hi
    
    Legacy BSD 'format' selection:
    
    h110: {295} % lpr -x /tmp/hi
    
    Format 'b' (Binary) or 'l' (Literal)
     for 'Passthrough' Operation - format 'l' is used
    
    h110: {295} % lpr -l /tmp/hi
    h110: {295} % lpr -b /tmp/hi
    
    Control file example:
        Hh110.private
        J/tmp/hi
        Lpapowell
        N/tmp/hi
        fdfA383h110.private  <- first letter is format
        UdfA383h110.private
   

The lpr -Fx (Filter x) option allows you to specify the filter type. Which, of course, if you use the :filter option is ignored. The Binary or Literal (-b or -l requests Pass Through treatment from the filter. The filter is still used, but it is passed a special flag.

In the control file, lines starting with lower case letters specify a format and the data file to print with the format.

Figure 5-4. Filter Execution Environment

    lp:sd=/var/spool/lpd/%P
      :filter=/filter
      :lp=/dev/lp
    
    Execution:
      CWD is spool directory (/var/spool/lpd/lp)
    
    Environment:
      PATH=...               - from /etc/lpd.conf
      LD_LIBRARY_PATH=...    - from /etc/lpd.conf
      PRINTER=lp
      PRINTCAP_ENTRY=lp:        - printcap entry
        :sd=/var/spool/lpd/lp     with %P fixed up
        :filter=/filter
        :lp=/dev/lp
      CONTROL=Aroot@h110+383    - job control file
        CA
        D2001-10-19-06:40:59.968
        Hh110.private
        J/tmp/hi
        Lroot
        Proot
        Qlp
        N/tmp/hi
        fdfA383h110.private
        UdfA383h110.private

The PRINTCAP_PATH environment variable has new lines before every colon (:) so you can split it up easily in the filter. See Figure 3-14 for an example of this use. The CONTROL value is the job control file. The control file contains the job print request sent to lpd. The output device is opened Read-Write if the :rw flag is set and it is a real device. Also, if the output is a filter or network connection then then the output is Read-Write.

Figure 5-5. Command Line Options

    lp:sd=/var/spool/lpd/%P
      :filter=/filter
      :lp=/dev/lp
    
    /filter <dfA383h110.private >/dev/lp
         STDIN, STDOUT, STDERR to Filter_status
    
    -CA -D2001-10-19-06:40:59.968 -Hh110.private -J/tmp/hi -Lroot -Qlp
         From the control file
    
    -Plp -Ff
     Legacy and LPRng, -P printer, -F format
    
    -n root -h h110.private -f dfA383h110.private
       ...
     there are more lower case options than you want to think about
   

The filter command line options are really agressive due to history and feeping creaturism. All of the lines in the control file with a capital letter are passed as shown, the -F is used for the print job format, and the -c is set if the job format was l (Binary or Literal). The -f also is the name of the data file. STDIN is set to the data file and STDOUT to the output device or network connection. Just to make life interesting, the name of the accounting file (if it is specified in the printcap or if it has a default value) is passed as the last parameter.

Figure 5-6. Filter Exit Codes

    Exit Code                Action
    0 (JSUCC)                Successful, send filter output to printer
    1 (JFAIL)                Failed, retry later
    2 (JABORT)               Failed, do not retry, and Abort printing
    3 (JREMOVE)              Remove job
    4 (JHOLD)                Set job HOLD flag

The filter program exit codes can be used to control how the job is processed. The JSUCC (0) value is the normal successful exit code. The JFAIL (1) value is used to indicate some sort of temporary failure and the job should be retried again. The JABORT (2) is more serious, and indicates some system error. The job should not be retried and printing should stop. The JREMOVE (3) code simply removes the job. This is useful if the job is unprintable. Finally, the JHOLD sets the job HOLD flag. The job will not be released for printing until the lpc release command releases it.

Figure 5-7. Solid As A Rock Filter Operation

    Filter:
      - examines input format using file
      - decides if file format is compatible with printer
          if not, can run a conversion program to convert
          the output.
      - initializes printer by sending magic cookies to it
          magic cookies depend on particular device, model, etc.
      - transfers output to printer, optionally inserting various
          control codes, CR -> CR/LF
      - if printer can reports status, then gets status as it does
          the transfer operation.
      - after transferring job,  sends more magic cookies to tell
          printer that job is over
      - monitors printer for error status
      - exits with an app