Click here!

SEARCH: Upload    Contact    Home



Start Here:

 
 
* Howto's
* Man Pages
* FAQ's
* Guides
* Search


* Software
* Index
* Distributions
* Howto
* Linux News
* Mailing Lists
* What's New

 
 

 
   

Console  GNOME   KDE   X11    Themes

 

TUCOWS Linux
Printing-HOWTO-7
The Linux Printing HOWTO: How to set things up Next Previous Contents

7. How to set things up

For common configurations, you can probably ignore this section entirely - instead, you should jump straight to the Vendor Solutions section below, or better yet, your vendor's documentation. Most Linux distributions supply one or more "idiot-proof" tools to do everything described here for common printers.

If your vendor's tool's results are not satisfactory, or you'd like the ability to interactively control printing options when you print, then you should use PDQ; I recommend PDQ in most cases.

7.1 Configuring PDQ

PDQ can be configured by either the superuser or by a joeuser. Root's changes are made to /etc/printrc, and affect everyone, while joeuser can only modify his personal .printrc. Everything applies to both types of configuration.

If PDQ is not available prepackaged for your distribution, you should obtain the source distribution from the PDQ web page and compile it yourself. It is an easy compile, but you must first be sure to have installed the various GTK development library packages, the C library development package, the gcc compiler, make, and possibly a few other development things.

Drivers and Interfaces

PDQ lets users select a printer to print to. A printer is defined in PDQ as the combination of a "driver" and an "interface". Both drivers and interfaces are, in fact, merely snippets of text in the PDQ configuration file.

A PDQ interface says everything about how to ship data out to a printer. The most common interfaces, which are predefined in the PDQ distribution's example printrc file, are:

local-port

A local port interface speaks to a parallel or serial port on the machine PDQ is running on. Using this interface, PDQ can print directly to your parallel port. Note that if you have a multiuser system this can cause confusion, and if you have a network the local-port interface will only apply to one system. In those cases, you can define a raw unfiltered lpd queue for the port and print to the system's lpd daemon exactly the same way from all systems and accounts without any troubles. This interface has a device name argument; the typical value would be /dev/lp0.

bsd-lpd

A bsd lpd interface speaks over the network to an LPD daemon or LPD-speaking networked printer. PDQ supports job submission, cancellation, and queries to LPD interfaces. This interface has hostname and queuename arguments.

appletalk

The appletalk interface allows you to print to printers over the Appletalk network; if you have a printer plugged into your Mac this is the way to go. This interface needs to have the Netatalk package installed to work.

A PDQ driver says everything about how to massage print data into a format that a particular printer can handle. For Postscript printers, this will include conversion from ascii into Postscript; for non-Postscript printers this will include conversion from Postscript into the printer's language with Ghostscript.

If one of PDQ's included driver specifications doesn't fit your printer, then read the section below on how to write your own.

Defining Printers

To define a printer in PDQ:

  • First check that you've got suitable driver and interface declarations in the system or your personal printrc.
  • If you want to define the printer in /etc/printrc (for all users), then su to root.
  • Run xpdq, and select Printer->Add printer. This "wizard" will walk you through the selection of a driver and interface.
That's really all there is to it; most of the work lies in finding or creating a suitable driver specification if you can't find one premade.

Creating a PDQ Driver Declaration

Here I'll walk through an example of how to make a PDQ driver declaration. Before you try that, though, there are several places to look for existing driver specs:

  • PDQ itself comes with a small collection of prewritten driver files.
  • This HOWTO's database includes a program called "PDQ-O-Matic" which will generate a PDQ specification from the information in the database. With a bit of fiddling, this may suit. This is the easy path if you have a non-Postscript printer.
  • I've written a tool called ppdtopdq which takes a Postscript Printer Definition file and converts it into a PDQ driver specification. This is the obvious path if you have a Postscript printer. Mail me for a copy.

There are several places to look for the information needed to write your own PDQ driver:

  • The PDQ driver specification syntax is quite rich, and is fully documented in the printrc(5) man page.
  • The PDQ distribution includes a few example files. Look in particular at the Epson Stylus file, which demonstrates the structure of the definition for a Ghostscript-driven printer.
  • The Printing HOWTO Database includes raw Linux driver information for over 400 printers. This will tell you what options to give Ghostscript, or what extra program to run on the Ghostscript output.

If you have to create your own driver specification, or if you enhance one from the PDQ distribution or one of the PDQ driver generator programs mentioned above, please share your creation with the world! Send it to me (gtaylor+pht@picante.com), and I'll make sure that it gets found by future PDQ users with your type of printer.

Now, let's walk through the writing of a driver specification for a printer listed in the Printing HOWTO's database as working, but for which you can't find a PDQ driver spec. I'll use the Canon BJC-210 as the example printer.

First, we look at the database entry for this printer. Note that it is supported "perfectly", so we can expect to get comparable results (or better) to Windows users. The important information is in three places in the entry:

Driver

The last line in the Works?/Language/Driver column tells us one driver that works with this printer. More importantly, this name is a link to the driver's home page.

Notes

The human-readable notes will often contain useful information. For some printers, there is a More Info link, which usually refers to a web page run by a user with this printer, or to the driver's home page.

Driver List

Most printers have a list of driver command data. This is the most important part.

A PDQ driver spec has two logical functions: user interaction, and print job processing. These are represented in the file in three places:
Option Declarations

These define what options the user can set, and declare PDQ variables for later parts of the driver to use.

Language Filters

These process the print job from whatever format it arrived in (typically Postscript or ASCII) into a language the printer can understand (for example, PCL). Option values are available here, as well as in the output filter.

Output Filter

This final filter bundles up the printer data regardless of input type; often printer options are set here.

Let's work on each of these for a Canon BJC-210:

Options

The driver list for this printer looks like this:

Driver: Ghostscript: -sDEVICE=bj200 -r360x360   # (360x360 BW)
Driver: Ghostscript: -sDEVICE=bjc600 -r360x360  # (360x360 Color)

The database's documentation tells us that a "Ghostscript" driver type's text is a set of options for Ghostscript, less the "usual" options like -q or the file specifying options.

So, as far as the user is concerned, the BJC-210 supports one useful option: the user should pick color or black-and-white. Let's declare that as choice option called "MODE":

option {
  var = "MODE"
  desc = "Print Mode"
  # default_choice "Color"    # uncomment to default to color
  choice "BW" {
    # The value part assigns to the variable MODE whatever you 
    # want. Here we'll assign the text that varies between the 
    # two Ghostscript option sets for the two modes.
    value = "bj200"
    help = "Fast black printing with the black cartridge."
    desc = "Black-only"
  }
  choice "Color" {
    value = "bjc600"
    help = "Full-color printing."
    desc = "Color"
  }
}
With the above choice declarations, the user will see a Color or BW choice in the driver options dialog when he prints from xpdq. In the command-line pdq tool, he may specify -oBW or -oColor. The default can be set from xpdq, or declared above with the default_choice keyword.

Language Filtering

PDQ normally identifies its input with the file(1) command. For each type returned by file that you want to handle, you provide a language_driver clause. The clause consists mostly of a script to process the printjob language, in any (!) scripting language you wish (the default is the usual Bourne shell).

In our case, we want to print Postscript and ASCII on our BJC-210. This needs two language drivers: one to run Ghostscript for Postscript jobs, and one to add carriage returns to ASCII jobs:

# The first language_driver in the file that matches what file(1) 
# says is what gets used.
language_driver ps {
  # file(1) returns "PostScript document text conforming at..."
  filetype_regx = "postscript"
  convert_exec = { 
    gs -sDEVICE=$MODE -r360x360 \     # gs options from the database
       -q -dNOPAUSE -dBATCH -dSAFER \ # the "usual" Ghostscript options
       -sOutputFile=$OUTPUT $INPUT    # process INPUT into file OUTPUT

    # Those last two lines will often be the same for gs-supported
    # printers.  The gs... line, however, will be different for each
    # printer.      
  }
}

# We declare text after postscript, because the command "file" will
# often describe a postscript file as text (which it is).
language_driver text {
  # No filetype_regx; we match the driver's name: "text"
  convert_exec = {#!/usr/bin/perl
     # a Perl program, just because we can!
     my ($in, $out) = ($ENV{'INPUT'}, $ENV{'OUTPUT'});
     open INPUT, "$in";
     open OUTPUT, ">$out";
     while(<INPUT>) {
        chomp;
        print OUTPUT, "$_\r\n";
     }
  }
}

That's it! While other printers may need output filtering (as described in the next section), the above clauses are it for the BJC-210. We just wrap them all up in a named driver clause:

driver canon-bjc210-0.1 {
  option {
    var = "MODE"
    desc = "Print Mode"
    # default_choice "Color"    # uncomment to default to color
    choice "BW" {
      # The value part assigns to the variable MODE whatever you 
      # want. Here we'll assign the text that varies between the 
      # two Ghostscript option sets for the two modes.
      value = "bj200"
      help = "Fast black printing with the black cartridge."
      desc = "Black-only"
    }
    choice "Color" {
      value = "bjc600"
      help = "Full-color printing."
      desc = "Color"
    }
  }

  # The first language_driver in the file that matches what file(1) 
  # says is what gets used.
  language_driver ps {
    # file(1) returns "PostScript document text conforming at..."
    filetype_regx = "postscript"
    convert_exec = { 
      gs -sDEVICE=$MODE -r360x360 \     # gs options from the database
         -q -dNOPAUSE -dBATCH -dSAFER \ # the "usual" Ghostscript options
         -sOutputFile=$OUTPUT $INPUT    # process INPUT into file OUTPUT

      # Those last two lines will often be the same for gs-supported
      # printers.  The gs... line, however, will be different for each
      # printer.      
    }
  }

  # We declare text after postscript, because the command "file" will
  # often describe a postscript file as text (which it is).
  language_driver text {
    # No filetype_regx; we match the driver's name: "text"
    convert_exec = {#!/usr/bin/perl
       # a Perl program, just because we can!
       my ($in, $out) = ($ENV{'INPUT'}, $ENV{'OUTPUT'});
       open INPUT, "$in";
       open OUTPUT, ">$out";
       while(<INPUT>) {
          chomp;
          print OUTPUT, "$_\r\n";
       }
    }
  }
}

Output Filtering

If you want to prepend or append something to all printjobs, or do some sort of transformation on all the data of all types, then it belongs in the filter_exec clause. Our little Canon doesn't require such a clause, but just to have an example, here's a simple illustration showing how to support duplexing and resolution choice on a Laserjet or clone that speaks PJL:

driver generic-ljet4-with-duplex-0.1 {
  # First, two option clauses for the user-selectable things:
  option {
    var = "DUPLEX_MODE"
    desc = "Duplex Mode"
    default_choice = "SIMPLEX"
    choice "SIMPLEX" {
      value = "OFF"
      desc = "One-sided prints"
    }
    choice "DUPLEX" {
      value = "ON"
      desc = "Two-sided prints"
    }
  }

  option { 
    var = "GS_RES"
    desc = "Resolution"
    default_choice = "DPI600"
    choice "DPI300" {
      value = "-r300x300"
      desc = "300 dpi" 
    }
    choice "DPI600" {
      value = "-r600x600"
      desc = "600 dpi" 
    }
  }

  # Now, we handle Postscript input with Ghostscript's ljet4 driver:
  language_driver ps {
    filetype_regx = "postscript"
    convert_exec = { 
       gs -sDEVICE=ljet4 $GS_RES \
          -q -dNOPAUSE -dBATCH -dSAFER \
          -sOutputFile=$OUTPUT $INPUT
    }
  }

  # Finally, we wrap the job in PJL commands:
  filter_exec {
    # requires echo with escape code ability...
    echo -ne '\33%-12345X' > $OUTPUT

    echo "@PJL SET DUPLEX=$DUPLEX_MODE"    >> $OUTPUT
    # You can add additional @PJL commands like the above line here.
    # Be sure to always append (>>) to the output file!

    cat $INPUT >> $OUTPUT
    echo -ne '\33%-12345X' >> $OUTPUT
  }
}

7.2 Configuring LPD

Most Linux systems ship with LPD. This section describes a very basic setup for LPD; further sections detail the creation of complex filters and network configuration.

Traditional lpd configuration

The minimal setup for lpd results in a system that can queue files and print them. It will not pay any attention to wether or not your printer will understand them, and will probably not let you produce attractive output. Nevertheless, it is the first step to understanding, so read on!

Basically, to add a print queue to lpd, you must add an entry in /etc/printcap, and make the new spool directory under /var/spool/lpd.

An entry in /etc/printcap looks like:

# LOCAL djet500
lp|dj|deskjet:\
        :sd=/var/spool/lpd/dj:\
        :mx#0:\
        :lp=/dev/lp0:\
        :sh:
This defines a spool called lp, dj, or deskjet, spooled in the directory /var/spool/lpd/dj, with no per-job maximum size limit, which prints to the device /dev/lp0, and which does not have a banner page (with the name of the person who printed, etc) added to the front of the print job.

Go now and read the man page for printcap.

The above looks very simple, but there a catch - unless I send in files a DeskJet 500 can understand, this DeskJet will print strange things. For example, sending an ordinary Unix text file to a deskjet results in literally interpreted newlines, and gets me:

This is line one.
                 This is line two.
                                  This is line three.
ad nauseam. Printing a PostScript file to this spool would get a beautiful listing of the PostScript commands, printed out with this "staircase effect", but no useful output.

Clearly more is needed, and this is the purpose of filtering. The more observant of you who read the printcap man page might have noticed the spool attributes if and of. Well, if, or the input filter, is just what we need here.

If we write a small shell script called filter that adds carriage returns before newlines, the staircasing can be eliminated. So we have to add in an if line to our printcap entry above:

lp|dj|deskjet:\
        :sd=/var/spool/lpd/dj:\
        :mx#0:\
        :lp=/dev/lp0:\
        :if=/var/spool/lpd/dj/filter:\
        :sh:
A simple filter script might be:
#!perl
# The above line should really have the whole path to perl
# This script must be executable: chmod 755 filter
while(<STDIN>){chop $_; print "$_\r\n";};
# You might also want to end with a form feed: print "\f";
If we were to do the above, we'd have a spool to which we could print regular Unix text files and get meaningful results. (Yes, there are four million better ways to write this filter, but few so illustrative. You are encouraged to do this more efficiently.)

The only remaining problem is that printing plain text is really not too hot - surely it would be better to be able to print PostScript and other formatted or graphic types of output. Well, yes, it would, and it's easy to do. The method is simply an extention of the above linefeed-fixing filter. If you write a filter than can accept arbitrary file types as input and produce DeskJet-kosher output for each case, then you've got a clever print spooler indeed!

Such a filter is called a magic filter. Don't bother writing one yourself unless you print strange things - there are a good many written for you already on the net. APS Filter is among the best, or your Linux distribution may have a printer setup tool that makes this all really easy.

There's one catch to such filters: some older version of lpd don't run the if filter for remote printers, and some do. The version of lpd with modern Linux distributions, and FreeBSD does; most commercial unices that still ship lpd have a version that does not. See the section on network printing later in this document for more information on this.

Accounting

Some installations need to keep track of who prints how much; this section summarizes methods for doing this.

Regular LPD provides very little to help you with accouting. You can specify the name of an accounting file in the af= printcap attribute, but this is merely passed as an argument to your if= filter. It's up to you to make your if= filter write entries to the accounting file, and up to you to process the accounting file later (the traditional format is mainly useful for line printers, and is nontrivial to parse in Perl, so there's no reason to preserve it).

Ghostscript provides a PageCount operator that you can use to count the number of pages in each job; basically you just tack a few lines of postscript onto the end of the job to write an accounting file entry; for the best example of this see the file unix-lpr.sh in the Ghostscript source distribution.

Note that the unix-lpr implementation of accounting writes to a file from the Ghostscript interpreter, and is thus incompatible with the recommended -dSAFER option. A better solution might be to query the printer with a PJL command after each job, or to write a postscript snippet that prints the pagecount on stdout, where it can be captured without having to write to a file.

The LPRng print spooler includes an HP-specific sample implementation of accounting; I assume that it queries the printer with PJL.

Large Installations

Large installations, by which I mean networks including more than two printers or hosts, have special needs. Here is a description of one possible arrangement.

  • Each printer should have a single point of control, where an administrator can pause, reorder, or redirect the queue. To implement this, have everyone printing to a local server, which will then queue jobs and direct them to the proper printer.
  • Use LPRng, at least on servers; the BSD LPD is too buggy for "real" use.
  • Client systems should not have unique printing configurations. To implement this, use LPRng's extended printcap syntax so that you have one printcap to use everywhere.
  • Print queues should not be named for make or model; name print queues for something sensible like location (floor2_nw) or capability (color_transparency). Three years from now, when a printer breaks, you will be able to replace it with a different make or model without causing confusion.
  • Operate a web page which shows detailed information on each printer, including location, capabilities, etc. Consider having it show the queue. Complex networked environments are unmanagable for users without proper documentation.
  • On Unix systems, use PDQ to allow selection of print job attributes such as duplex or paper size, and to force users to run all Ghostscript processing under the proper user ID.
  • On Windows and Apple systems, use either the platform-specific drivers everywhere (Samba supports the Windows automagical driver-download mechanism) or use generic Postscript drivers everywhere. Do not mix and match; primitive word processors often produce different output when the installed printer driver changes; users cannot deal with output that vaires depending on the particular client/printer pair.
  • If at all possible, buy a large-volume printer for large-volume printing. If on a budget, use LPRng's multiple printers/one queue facility and assign a babysitter; printers are complex mechanical devices that will often jam and run out of paper in such configurations.
  • Do not feel that printers must be plugged into workstations; Ethernet "print servers" now cost under $100. The ability to locate printers anywhere you can network is a big improvement over forced location near a host; locate printers in sensible, central locations.

File Permissions

By popular demand, I include below a listing of the permissions on interesting files on my system. There are a number of better ways to do this, ideally using only SGID binaries and not making everything SUID root, but this is how my system came out of the box, and it works for me. (Quite frankly, if your vendor can't even ship a working lpd you're in for a rough ride).

-r-sr-sr-x   1 root     lp    /usr/bin/lpr*
-r-sr-sr-x   1 root     lp    /usr/bin/lprm*
-rwxr--r--   1 root     root  /usr/sbin/lpd*
-r-xr-sr-x   1 root     lp    /usr/sbin/lpc*
drwxrwxr-x   4 root     lp    /var/spool/lpd/
drwxr-xr-x   2 root     lp    /var/spool/lpd/lp/

Lpd must currently be run as root so that it can bind to the low-numbered lp service port. It should probably become UID lp.lp or something after binding, but I don't think it does. Bummer.

PDQ uses a different, non-daemon-centric scheme, so it has different programs. The only SUID root programs are the lpd interface programs lpd_cancel, lpd_print, and lpd_status; these are SUID because actual Unix print servers require print requests to originate from a priviledged port. If the only printers for which you use PDQ's bsd-lpd interface are networked print servers (like the HP JetDirect or Lexmark's MarkNet adapters) then you do not need the suid bit on these programs.


Next Previous Contents

News   Contact   Advertise   CD ROM   Search   Upload   Help   Home


Copyright © 2000 TUCOWS.COM Inc.
TUCOWS.COM Inc. has no liability for any content or goods on the TUCOWS site or the Internet, except as set forth in the terms and conditions and privacy statement.