The SCO UNIX print spooler, (also called the print service or print
scheduler), is a collection of commands and utilities that are used
to administer and access printers. These can be printers attached
locally to your machine or ones that are attached to remote machines.
The only thing most users think about is what they see: the
beginning and ending of the print process. There is the lp
command, which sends the print request and there is the final output
on paper. However, the print spooler does more that just accept the
jobs and send the data to the printer. In fact, it has quite a lot to
Among the things that the print spooler is responsible for are:
receiving the data users want to print (either as names of files or
the end of a pipe), schedules the job on the printer, maintaining the
status of each job on each printer, interfacing directly with the
printer (actually the device node associated with the printer) and
sending you messages when things go wrong.
The Print Process
When you print a file, (either by using the lp
command to specify a file or as the end of a pipe) the print spooler
assigns that request (or job) a unique identifier. This identifier
consists of the printer name and the number of the print request.
Next, the print spooler puts the job into a queue (a waiting
line) to be printed. Each job must wait until the printer is ready.
That is, each job must wait until the previous job is completed.
Otherwise you end up with jobs printing on top of each other. The
process of placing the print job into a "print queue" is
called "spooling". Since each printer has it's own queue,
problems with one printer will not (usually) effect others.
For each job the print spooler creates two files that describe the
job request and places one in the /usr/spool/lp/temp
directory and one in the
/usr/spool/lp/requests directory. The reason for splitting the
files like this is for security reasons. The /usr/spool/lp/temp
directory is accessible to everyone. The information contained here
is just the necessary information for you to monitor your own jobs.
As a normal user you do not have access to the /usr/spool/lp/requests
Once the jobs are printed, these files are removed and the
information they contain is combined and placed in the "request
Since the information is the same, in the working files and log
files, if know how to read one, (that is, what each line means) you
know how to read both. The files in temp
and request contain the
information for just a single job. When combined into the request
log, entries are separated by a line starting with an equal-sign and
containing the job_ID, UID, GID, total number of bytes and the data
and time the job was queued. Table 0.1 contains a list of what each
of these lines mean.
Either a printer or a class of printers (more on that later)
of the file. If a copy is made this will be a name in
/usr/spool/lp/temp. If no copy is made this will be the full path
of the file. If multiple files were queued, then there with be
multiple 'F" lines.
name used (if one is specified). (More on forms later.)
handling, such as resume, hold or immediate
When the job is finished, should the user get an email message or
have a message written to the terminal.
given to lp with -o.
of the print job (if applicable).
of pages printed.
processing options (if any) given to lp
set or print wheel used
Success of the job, expressed as a combination of bits in hex
0x0004 Slow filtering finished successfully.
Printing finished successfully.
Request was canceled.
0x0100 Request failed
filtering or printing.
on the banner page.
of file content
who submitted the print job.
modes to give to the filters. Fast filter
used for the request. This only differs from the destination (the
D line) if the request was queued for ``any'' printer or a class
of printers, or if the request is transferred to another printer.
0.1 Contents of Printer Spooler Working and Log
There may come a time when you send a job to a printer and
after some time, there is still no output. You wonder what happened
to your print job and what to take a look at the status. This can be
done with the lpstat
command or also the Print Job Manager if you are running OpenServer.
If you use lpstat by
itself, it will just show you the status of your own jobs. If you
use the '-t' option, you will not only see all the jobs, but you will
see the complete status information for the entire print spooler.
Personally, these are the only two ways I have ever used
lpstat. However, it does
have several different options that may be useful to you in specific
circumstances. Therefore, you might want to take a look at the
man-page when you get a chance.
When I run lpstat
-t on my system, I get:
default destination: DeskJet
for DeskJet: /dev/lp0
for Panasonic: /dev/lp1
accepting requests since Tue May 23 20:07:37 1995
accepting requests since Fri May 26 16:16:54 1995
DeskJet is idle. enabled since Fri May 26 16:00:05 1995. available.
Panasonic is idle. enabled since Fri May 26 16:16:54 1995. available.
root 908 May 26 14:54
The first line from lpstat
tells us whether the print scheduler is running or not. The second
line tells us what the system default printer is. The default printer
is where the print spooler sends jobs if we don't tell it where the
print job should go by using the -d
option to lp. This is
useful information because users will sometimes think the spooler
swallowed their print jobs because they don't come out where they
want. I have had enough calls from customers saying that the spooler
worked with only one type of printer or there was some built-in limit
to the number of printers. It always turned out that they didn't
check to see what the default was and their job was going somewhere
they didn't expect.
Next is a list of the printers and the associated devices.
Keep in mind that just because a device is listed here, does not mean
that there is a physical connection to the device or the device
exists at all. It could be that the printer was configured for a
particular device, but that device doesn't exist on that system or
the device is now broken. The reason is that lpstat
does not do any checking of the physical device. It simply reads the
configuration file for each printer and outputs the device specified.
This information is found in
is the name you gave to that printer.
Next is a list of the printers, detailing which are accepting
requests/not accepting requests and which are enabled/disabled. Like
the information for the device, the print spooler maintains this
information in a file. In this case file is
Each entry is started with a row of equal-signs (=). This is followed
by the printer name, etc. My file looks like this
As you can see, my DeskJet is currently disabled. When I disabled it
prior to looking at these files, I didn't specify a reason.
Therefore, you see the "unknown reason" as the sixth line
of this entry. If I were to run lpstat
-t again, I would get an entry that looked like this:
printer DeskJet disabled since
Fri May 26 16:21:55 1995. available.
Which is essentially the same information as in this file. The
entries "new destination” and "new printer”
are there because they are new I have never disabled them or
rejected requests on them.
If you are a point-n-click person, then this information is
obtainable from Printer Manager. If you want to find out the status
of print jobs, you need to run the Print Job Manager. Under the
"View" menu you can choose to look at the jobs by user or
by queue or even all of the jobs if you want. Here, you can also
hold jobs, transfer them to other printers, "promote" them
by placing them at the head of the queue and even delete jobs. All of
these required commands other than lpstat.
The thing that bothers me personally is that the Print Job Manager
will only tell you about print jobs. (I guess that's why they called
it Print Job Manager) If you start up the Print Job Manager and see
that a job has been waiting for three days to be printed, you get
nothing to tell you why. You see what printer the job is destined for
(what queue it is in), but in order to find out why that queue is
not going anywhere you need to run the Printer Manager. (If the job
has been "put on hold" you will see a "held" in
the status column in the Print Job Manager)
Now, I am not knocking either the Print Job Manager or the Printer
Manager. Both provide a GUI that makes configuring and administering
printers much easier than before. Even the CHARM interface is useful
and easy to use. However, when problems arise, I want to see
everything in one place. Therefore, I will continue to use my old
Administration of printers has been simplified to a great extent by
the graphics interfaces provided by the Print Job Manager and the
Printer Manager. Now it is a simple matter of pointing and clicking
to delete jobs, move them to other printers, or put them on hold. If
you are root or a user with lp authorization (see the section on
Security) you can administer all the jobs on the system, not just
your own. If you are just a "regular" user, that is one
without lp authorization, then many of the options in the Print Job
Manager will be "dimmed". This means that they are
inaccessible to you.
When you delete a job under the Print Job Manager (assuming you have
the authorization to) the "Status" column briefly changes
to 'canceled' before the job disappears from display. This is the
same thing as if you were to run cancel from the command line.
Maybe there is a print job that is exceptionally large and you want
to let other, smaller jobs go first. One alternative is to use the
Print Job Manager to promote the other jobs above the large one. If
you want just a few just printed quickly before "allowing"
the larger one to print, then this is a valid option. However, what
if there are jobs constantly coming in and you want to wait until
lunch time or the end of the day before you let this job go through?
The answer is to put that job on hold. This means that the job will
not be printed until you tell the spooler to do so. This can be
accomplished in a couple of ways. First you can use the lp command
itself. Either you specify the option as '-H hold' when you submit
the print request or you tell the spooler to hold a specific job, as
lp -i DeskJet-42 -H hold
The '-i' option is to specify the Job-ID. This example would put on
hold job DeskJet-42.
The other alternative is to use the Print Job Manager. First , click
on the job you want to hold, then under the 'Jobs' menu, there is an
entry 'Hold'. If the job is already on hold, or you do not have
authorization, then this item is "dimmed" (disabled). Once
you have done either of these procedures, then the entries in both
the Print Job Manger and lpstat
change to reflect this.
If we now looked in the status file for this print job, we would now
see a change in its contents to reflect the fact the job is being
held. For example, if I wanted to put on hold a 50-page letter to my
friend Tillman, the status file might look like this before I put it
and like this, afterward:
Notice that in the first output, there is no reference to being held
or anything similar. This is because I didn't specify any hold
option. If I later decide that I want to resume the job, I can take
it off hold by telling the print spooler to resume. This is done
through either the Resume entry in the Jobs menu of the Print Job
Manager or from the command like this:
lp -i DeskJet-42 -H resume
The status column in the Print Job Manager is cleared and the job
will now print. If we look in the status file, we see the H entry
has changed from:
From our perspective, the job is as it was when we started.
Therefore, the status file should look the same, shouldn't it?
Well, from the spooler's perspective the status of the printer is
that it is no longer held, but rather in resume status.
Therefore the status of the print job is different from the
spooler's point of view.
You can hold jobs that are currently printing, as well as jobs that
are further back in the queue. When you resume a job whose turn has
passed, it will become the first job to print (after the current one
finishes). I have had occasion to use this option when printing a
large file that I want to stop in order to print something smaller
that I need right away. When I resume the job, it will begin printing
from the first page and not where it left off. This is because the
print spooler does not keep track of how many pages it has printed.
If you want to avoid having to print everything over again, you can
use the -P option to lp to
tell the spooler, what page to start from, like:
lp -i DeskJet-42 -H resume -P 16
In this example, the spooler would resume printing job DeskJet-42,
but would do so starting on page 16.
Actually I should say that the spooler "could" resume
printing starting on page 16. Remember that I said that the spooler
does not keep track of how many pages it printed. In order to start
somewhere other than the beginning of the file, you will need a
printer filter that can.
The job status files also change when you move a print job to a
different printer. It is often necessary to move print jobs for
several reasons. First, one queue may become backed up, even if you
have set up printer classes (groups of printers). I was convinced
that there is a build in mechanism with the print spooler that looked
for the busiest printer and send all the jobs there. When I
was working in SCO support, all the jobs that I submitted ended up
going to the printer that was in the process of printing a hundred
page report. This similar to the phenomena at grocery stores that no
matter how many times you change lines, yours is always moving this
slowest. However, it was just my bad luck as the print spooler simply
chooses each printer in turn.
There are two ways to move a print job. Either use the Transfer entry
in the jobs menu of the Print Job manager, or use lpmove from the
command line. Using either one, you can transfer/move to either a
specific printer or to a printer class.
If you look back at the example status file, you will see that the
destination (specified by the D) is set to DeskJet. If we move that
print job (DeskJet-42) to the Panasonic printer, the entry in
now looks like:
If we do lpstat a
or look at the Print Job Manager at this point, the job-ID is still
DeskJet-42. The job ID is given when the job is first queued up. It
never changes. Even when we move the job to a different printer, it
keeps the same ID. This often confuses system administrators who
expect the job-ID to be dependent on the printer queue.
When I first started talking about putting jobs on hold, I mentioned
that you could move jobs up the queue, or promote them. This is done
through the print Job Manager. If a job is currently being printed,
the only way to get another job to print first is to either cancel or
put the first job on hold, then promote the other. One problem exists
in that you cannot promote a job over the top of a job that has
already been promoted. Well, at least that's what the SCO doc says.
This is true when you first promote the job. However, I have found
that promoting a job a second time puts it at the top of the queue
However, putting jobs on hold and promoting them is not the
only way of determining the priority of jobs. The print spooler
provides a means to predetermine the priority of print jobs on a per
user basis. When a user submits a print job, they can assign a
"priority level", where jobs of higher priority are printed
first. These priorities are in the range 0-39, however root (or the
lp administrator) can set a limit on how high that priority can be.
Just like process priorities, users cannot give their jobs a higher
priority that allowed, but they can be nice and give themselves a
If needed, a default priority can be set so that users who do not
have a maximum set for them specifically cannot go to high. Also, a
system wide printer priority can be set. This is done with the
lpusers command. When
starting the job, use the -q
option to lp. By
specifying the job-ID with the -i
option to lp, you can
change the priority on jobs that are already queued.
Interface scripts are the means by which the system configures and
sends data to the printers. As their name implies there are shell
scripts that act as the interface to the physical printer. Depending
of what kind of printer is being accessed, the interface script can
be anywhere from a couple of kilobytes in size to over 10 times that.
The interface script is responsible for almost every aspect of the
print process. First, the interface script must configure the port
that the printer is connected to. This ensures that the port as the
proper settings such as baud rate, parity and flow control. This is
accomplished in the script by using the stty
Next the interface script initializes the physical printer. Often
this means restoring the printer a default state. This is necessary
in cases where a previous print job made changes to the font, pitch,
page size, etc and these values are not acceptable for the next job.
After preparing the port and the printer itself, the interface script
is ready to print the file. Often times the first thing it prints is
a banner page. This serves as a separator between print jobs. When
many different prints jobs are sent to a single printer, this can be
very useful since the banner page contains information such as the
name of the user who printed the file as well as the job-ID.
In each interface script, the format of the banner page is the same
and is created "on-the-fly" by the script. It is therefore
possible for you to edit the interface script and make any changes to
the format of the banner page you want. You can even remove the
portion of the script that creates to banner page to prevent it from
After printing the banner (if told to do so), the interface
script now prints the file. Keep in mind that the interface script
does not open the device port itself. Rather the interface script is
actually changing the settings and sending the file to stdout. It is
the print scheduler that opens the printer port which is then passed
to the interface script as stdout. If you look at the interface
script (which we'll do in a moment), you'll see that there is no
redirection of standard out. When the interface script is started,
stdin actually comes from /dev/null.
As the print job progresses, the interface script monitors the
progress to see if everything flows smoothly. If there are problems
it is responsibility of the interface script to report the problems
back to the print spooler. These are then made available to the user
through either lpstat,
sysadmsh the Print Job Manager.
When you install a printer, you need to choose a particular model
of printer to use. This refers to the interface script that will be
copied from /usr/spool/lp/model
with the name you have given to the printer you are installing. If
you don't have one of the printers that are listed, you can choose
one that comes close. For example, I have an HP DeskJet 540. Since
there was no interface script especially for this printer, I choose
the HPDeskJet model and have been very happy with the performance.
If there is nothing that matches even closely, there are two models
that are very useful: dumb and standard. The dumb interface script is
the smallest and does nothing to prepare either the port or the
printer itself. If your application is embedding all the printer
configuration commands in the file it's sending, then this is the
model to use even if the printer you have matches one of the
other models. This is so that the configuration commands to interfere
with each other.
Many of the interface scripts (including standard) have special
configuration options that you can use to change the behavior of the
printer. This are passed with the -o option to the lp
and include almost every conceivable characteristic such as
characters per inch, font, line spacing and orientation (portrait or
In each case these are sequences of characters that tell the printer
to change the characteristics. These sequences are the echoed to the
printer. For example, if you were using the epson model interface
script and used the option -obold
to turn on bold output, the epson interface script would echo the
character sequence "\033E\c". If this same sequence where
echoed to the printer port by another shell script or even from the
command line, the result would always be to have an Epson printer
turn on bold. If you were using the HPLaserJet script, then the
character sequence would be different. In most cases, the escape
sequences are in the document, so you don't need to worry about them.
If you have a printer that doesn't work right with any of the
existing interface scripts, you can modify one of the existing
scripts to create one of your own. If one of the existing interface
scripts matches closely, but is missing some important
characteristics, then modifying the existing script is probably very
To avoid confusion and to allow for the possibility that one day you
will have that kind of printer, the best thing is to make a copy of
the model interface script. Don't copy this by hand into the
directory by hand. Instead make a copy in the
directory. That way you can use them again.
Let's assume that you have an Epson compatible printer that has a few
more characters types than just the standard bold, italic, condensed,
etc. Each of these can be turned on with the -o option as in -obold,
which turns on bold. As I mentioned before, the actual mechanism to
turn on each of these characteristics is to simply echo the
appropriate character sequence. So, if we know the character sequence
for this new type face (check the printer manual) and by using the
same means (echoing that character sequence) we can change any
The portion of the interface script that does this is a loop that
goes through each option and echoes the appropriate character
sequence. The for loop
begins like this:
for i in $options; do
b|nobanner) banner=no ;;
Z002 begin \/\/\/\/
We see that every option is checked with the case
statement and if it matches, a variable may be set or something
echoes. if we have set the bold option, we see that the interface
script the sets the variable bold
to yes and echoes sequence
\033E\c. If we has a new
typeface (let's call it simply newtype),
that was stated by using the character sequence \033P\c,
we could add a new case statement like this:
More case statements like
this can be added if there are more characteristics that you want to
There are actually several different ways that you can print to
remote printers in SCO. In older systems you had a choice of using
UUCP to copy files then remotely execute a print command. As networks
become the order of the day, then came rmcd,
lpd and finally the HP Jet
Direct EFS. All of which have their uses and all of which we'll get
to. SCO supports dialup printers, where you use the UUCP facilities
to connect to a remote printer. This has the advantage of not needing
any specialized hardware other than a modem (and the printer, of
course). SCO also provides support for the Berkeley Remote Printing
Daemon, lpd. If the remote site doesn't support lpd, we can use a
little trick with rcmd (remote command) to access the print
facilities of remote machines. The HP Jet Direct EFS (which has been
subsequently included in the OpenServer product) allows direct access
to HP Laser Jet printer, provided they are equipped with the Jet
Direct Network card.
Printing with rcmd
The first method I want to talk about is perhaps the easiest to
configure. Another advantage it has is that it works on most any
system that understands the rcmd
command. This type of remote printing does have a name, per se, other
than "printing with rcmd." The principle is that we use the
rcmd command as the end of a pipe, which access the printer service
on the remote host. From the command line, if we wanted to print to
scoburg, it might look like this:
cat file_name | rcmd scoburg lp
If we wanted, we could also pass options to lp, by including the
entire command inside double quotes. For example,
cat file_name | rcmd scoburg "lp
One advantage this process has is that it does not require any
special configuration of the printer on the local side. The only
condition is that that the remote host can access the local machine.
The problem with it is that everyone needs to have access to the
remote host (either with user equivalence or .rhost files) and well
as they have to know the syntax of the rcmd. The solution is built
this functionality directly into the system. SCO provides an
interface script that does the work for you.
This is the network model printer interface script (or network.ps, if
you have a postscript capable printer). The first step is to create a
local printer using this interface. A couple of key things to
watch out for. First, the connection type should be set to "Direct”
and the Device the device should be "Hardwired.” Next,
specify /dev/null as the device you are printing to. Although you are
not actually printing through this device, you still need to specify
some device and /dev/null won't cause any problems.
Next, you need to create the file that sets up the command. This is
/usr/spool/lp/remote, the format of which is:
For example, I created one that looks like this:
remote: /usr/bin/rcmd siemau /usr/bin/lp -dlaser
Here the local printer name is remote. It will be using the
command /usr/bin/rcmd to execute the /usr/bin/lp command using the
destination printer laser. Since every thing after the local printer
name is considered part of the command, it is all passed to the
interface script. I can therefore include any options that I want.
If we look at the line in the interface script that actually does the
) | $network -s -ob $lpflags
The right parenthesis is the end of a fairly large block of code, the
output of which is piped to the $network
command. The $network
command is everything that appears after the printer name in the
The -s suppresses output messages from the lp command and the -ob
suppresses the banner. This is because the banner may be already
generated locally. (assuming you don't suppress it there, as
well). Finally, the $lpflags
is any options we passed to the lp
command from the command line.
Okay. So we are cat'ting
the output to the command defined in /usr/spool/lp/remote. Does it
have to be rcmd? No. In fact, we could pipe the output to something
like uux to get it to a remote print via UUCP. The syntax would be:
remote: /usr/bin/uux - siemau!/usr/bin/lp -dlaser
Here the ‘-' says to take stdin as the input file. We
then say we want to execute the command /usr/bin/lp on the machine
siemau, using the printer laser.
If you are using the first option, then you need to make sure the
rcmd works as the user lp on the remote side. This is done by either
having and /etc/hosts.equiv file or a .rhosts in the user lp's
home directory on siemau.
Printing with lpd
Remote printing using the lpd daemon falls under that heading of
Remote Line Printing (RLP). Although the central program is the lpd
daemon, I'll continue to use the term RLP as this describes the
entire package. RLP adheres to the client-server model, where
clients are sending print jobs to the servers that are doing the
RLP works a fair bit differently than "normal"
printing. Although you configure the printer in the same way, what
happens behind the scenes is different. The first thing is that three
of the standard SCO print commands (lp,
cancel, and lpstat,
with lpmove also include
in OpenServer) are moved from
replaced by new ones that understand remote printing. When you issue
one of these commands, they will check to see if the printer is local
or remote. If local, then the copy in
/usr/lpd/remote was executed.
On ODT 3.0, this was a problem when you "accidentally"
ran the configuration script (mkdev
rlp) twice, the original versions were replaced with the RLP
versions. When you issued one of these print commands, it would check
if the printer was local or not and, if so, would call the copy in
/usr/lpd/remote. Since this was also the RLP version , it
would check if the printer was local or not and, if so, would call
the copy in /usr/lpd/remote.
Since this was also the RLP version, it would check if the printer
was local or not and, if so, would call the copy in /usr/lpd/remote.
Since this was also the RLP version...
Figure 0-1 The
flow of LPD print requests
As a result, you would end up will a lot of processes taken up by the
program calling itself. There is an option in the
mkdev rlp script that removes the RLP functionality and copy
the files from /usr/lpd/remote
back into /usr/bin. The
problem was that this would not do any good as you were copying the
RLP files. The only solution was to restore the files from the
Assuming you have it configured correctly, when you issue one of
these three commands, RLP checks the file
/etc/printcap for configuration information about both the
local and the remote printer. If the printer is local, you can use
any of the standard print commands as the files in /usr/lpd/remote
are your original ones (or, at least, should be). If the printer is
remote, the print spooler invokes the lpd daemon, which sends the
print job over the network to the host specified in /etc/printcap.
Because of the connection across the network, administration and
certain printer functionality is limited. First, you cannot do remote
administration of the print queue, such as disabling it or moving
print jobs to other printers. This must be done locally, either
logging in directly or making a network connection using telnet,
rlogin or rcmd.
In addition, printer classes are also not supported.
RLP is installed using the mkdev
rlp script. You configure it using rlpconf.
When you run the script you have the choice of installing or
removing an existing printer. After creating the
/usr/spool/lpd directories, the script creates /etc/printcap
copies the three files in
/usr/spool/lpd/remote. You are then asked if you want to make
changes to the printer description file, which is
/etc/printcap, default. It is at this point that the mkdev
script calls rlpconf. If
you call rlpconf yourself
from the command line, you get to this exact same point.
Here you are prompted for the name of the printer and whether it is
local or remote. If you say remote, you are promoted for the name of
the remote printer. If local, you are asked for the name of the local
device. Note that this is not the name of an existing
local printer queue, but the name of a device. When you input this,
you are prompted to confirm what you input.
Keep in mind that this is all of the changes the rlpconf
command does to /etc/printcap.
If there are any special options that you wish to use, you have to
edit /etc/printcap by
hand. In general the syntax is:
If the first case (laser2), I can tell it is a remote printer. How?
Easy. The lp= variable tells you the name of the local device. Since
it is blank, there is no associated device, therefore notlocal. The rm= variable says what the name of the remote machine
is. Since it equals "siemau” in the case, I know it is
remote. In the second case, there is a device defined, but no remote
machine. Therefore, it is local. In both cases, we see the ex
option. This is just a Boolean varaible that says that lpd
can handle extended options. If this variable is present, it means
that the printer can handle extended options.
In the first entry we have the rp variable. This is the name of the
remote printer. Since the second entry defines a local printer, there
is no remote printer name. The sd variable, which is defined in both
entries is the name of the local spool directory. There are
over a dozen different options you can use. You can find out more
about this in the printcap(SFF) man-page.
In order for LPD to be working, the remote side needs to allow the
local printer to do so. This can be done in several ways and all
concern host equivalence. Host equivalence is a networking
topic that we go into details on chapter 14. The issue related to LPD
is that you can either set up user equivalence globally using the
/etc/hosts.equiv file or
set it up just for the lp user with the file /etc/hosts.lpd.
This file simply contains a list of the remote machines that are
authorized to print to this one using LPD. If you only need
equivalence to print, this gives them just what they need and nothing
Multiple Queues to the Same Printer
One common issue when printing is the problem when a single printer
needs to be accessed in two seperate ways. For example, you may want
to print one job in landscape mode and the next in portrait mode. If
you have a printer with multiple paper sources, you may want some
jobs on company letterhead and others on blank paper. If you have
access to the command line, you can pass he necessary options to the
lp command. Even if the
interface is not built with the appropriate functionality, you can
add the options to the interface as we talked about earlier.
What happens if you don't have access to the command line? In certain
companies, users will never see the command line. Maybe they are
brought into a menu to start on of several applications. Maybe the
application doesn't have the ability to switch between different
formats. Therefore, you need to rely on the operating system to do
the work for you.
We go from the assumption that there is no access to the command line
to print the file. Since, if we could, this whole section would be
superfluous. The basic idea is that we need to create names for the
same printer. This is based on the idea that from the operating
system's standpoint, a printer is only different in terms of it's
name and not the device.
Multiple print queues to the same printer
So what does that mean? Well, when you print to a printer, your print
job is queued. The print scheduled sends it to the physical port
"when it gets around to it." What physical port is used is
defined in the configuration
files in /usr/spool/lp/admins/lp/printers/<printer_name>.
Jobs being sent to a particular printer name are scheduled one after
the other. Such is the behavior of any queue.
If there are two printer names going though the same physical port,
the printer scheduler has no way of knowing. What could then happen
is two files are being sent to the same printer at the same time. The
result is that one job is interspersed with another. So, how do you
then get two printer names to go to the same port.
Well, one solution that I came up with while at SCO support was to
create two printers, just as you normally would. In each case you
specify the same device. In order to avoid the situation you need to
edit the appropriate interface script and have one printer first
disable the other, print the file, then re-able the other. The first
line of the interface script runs disable.
Since the interface script is run as the lp user, the script has the
authority to disable any printer. After finishing the print job,
enable is called to
re-enable that printer.
This mechanism is simple and fairly easy to implement. Although
unlikely, there is a potential for this not doing what it is supposed
to. What could happen is that the interface script is started,
but before the first line is executed (the one disbaling the other
printer), the process is context switched out. If the other script is
run, it disables the first printer. However, it's two late. The
interface script has already started and the 'disable' command only
effects the print scheduler and not the running process. When the
first job is context swicthed back in, it disables the second
printer. Again, this is too late. As a result, you have to printers
sending output to the same physical port at the same time.
Keep in mind that this is highly unlikely to happen. I have talked
with customer and even on system with "constant" printer
use, they have never seen merged print jobs. However, it is
So, how do prevent this? Well, you don't. The only way to keep the
system from merging print jobs likes this is to have only a single
printer access the port. The principal behind this is that you have
multiple "virtual" printers that each print to a single
printer, which, in turns, prints to the physical port. The virtual
printers are then configured to perform the needed functions.
For this, let's assume we have two parper sources. One containing
letterhead, which we will call "letter", and the only
containing plain paper, which we will call "plain".
Changing paper bins is not something that is contained within the
interface scripts that SCO provides. Therefore, we also need to
assume that we have made some changes to an interface script to allow
this functionality. Let's say that we have letterhead in the top bin,
so that option to access this bin will be -otop
and the plain paper is in the bottom bin, which we access with
the -obottom. Let's call
the "real" printer "deskjet"
The two "virtual" printers need to be configured using the
"network" interface and print to the device /dev/null.
This then allows us to edit the file /usr/spool/lp/remote
to print to the real printer with the necessary options. If
/usr/spool/lp/remote does not exist, you will need to create
it. In any event, add the lines:
letter: lp -ddeskjet -otop
lp -ddeskjet -obottom
If you remember from the discussion earlier on network printing, you
know that when we use the network interface we are actually piping
the output through a command. The command is what we have defined in
both of these cases The commmand we are using is simply lp. The key
is that we are sending each job to the same printer, but with
different option. Therefore, if your application cannot specify which
paper bin, you print to 'letter' to get letterhead or to 'plain' to
get plain paper.
When Things Go Wrong
There is a set of printer problems that commonly occurs. Some of them
can be solved by remaining calm and looking at your system. Others
require very simply changes. Unfortunately, not all problems fall
into this set. Sometimes there are printer problems that cannot be
quickly resolved. Although I do not advocate it as the only solution
to printer problems, removing and reinstalling the printer package is
a relatively quick answer and solves a lot of problems.
If you really want to find the cause of your problem, then obviously
removing the print package is not the answer. However, most of the
time, the customers I talked to did not want to know why it happened,
just what they could do to get printing again. I made it a rule that
I would work on a printer problem the same length of time as it would
take to remove and reinstall the printer package. Normally, this is
only about 20 minutes. If I was no where nearer the solution than
when I started, reinstalling was a good alternative.
Obviously, if you have 50 printers configured than removing and
reinstalling the printer package is probably not the best solution.
You probably spent hours configuring the printers and spending an
hour to solve the printer problem is a good investment.
If you decide that removing and reinstalling the printer package is
your best choice, there are a couple of things to consider. If you
are running RLP, then I would suggest that you first remove RLP
before you remove the entire print package. This is done by running
mkdev rlp and saying that
you want to delete remote printing. This ensures that the commands
used for remote printing end up in the right place.
The next issue is your existing printers. If you are using the
default interface scripts, then you are okay. However, if you have
made any modifactions to the interface scripts, then you should make
copies of them. When you reinstall the printer package, you can
simply replace the new interface scripts with your old ones. As a
side note, if you are upgrading from SCO Xenix, you can take
interface scripts from Xenix and use them on SCO UNIX, usually with
Another thing to consider is that you do not need to go
through sysadmsh or the
Printer Manager. The lpadmin
command will allow you to create printers from the command
line. For example, if I wanted to use the HPDeskJet interface and
create a printer called DeskJet, which is attached to /dev/lp0,
the command might look like this:
The -p option is the name
of the printer. The -m option
is the model printer we want to use. The -o
option is printing options that we want by default. In this
case, we specified "nobanner" to supress the banner page.
The -v says what device
the printer is attached to.
By creating a shell script that contained several lines, each
creating a new printer. You can quickly recreate all the printers you
removed. Doing it like this, even 50 can be recreated quickly. Fo
more details, see the lpadmin(ADM)
A common problem that does not require you to reinstall is
that the printer output appears to "stairstep." That is,
when the file is output, the text reached the end of the line, drops
down to the next line and continues printing without starting at the
beginning of the line. In other words, there is a newline without a
carriage-return. This normally happens on serial printers and the
reason for this is that the serial driver will reset the stty
settings on the line when that line is closed for the last time.
The solution is to create a script that keeps the line open. Such a
script is called a "hold-open" script. Actually, it is only
a single line that you can incorporate into an existing startup
script or one that you start by hand. A common place is
this is one of the last scripts execute befoer going into multi-user
mode, there is nothing that will interfer with it. The line would
look like this:
(stty <stty_settings> ;
while : ; do sleep 3600; done) < /dev/ttyXX &
Some suggestions for the <stty_settings>
include the baud rate, ixon, ixoff, and -ixany. You could also
explcitely tell the port to add a carriage return after all new-lines
with the setting onlcr. We
have inclosed the entire first portion within parenthesis so that it
is treated as a single command. Therefore, the stty settings are
made, and we go into a loop where we sleep for 3600 seconds (1 hour).
We then go to the top of the loop and sleep for another hour. This
holds the port (/dev/ttyXX) open
and holds the stty settings the way we want them. We then place the
entire command in the background.
Another common problem is the print scheduler stopping. Although this
is not all that common a problem in the sense that it happens
regualrly. It is common in the sense that it results in calls to SCO
Support. The administrator may see that the print scheduler has
stopped and try to restart it. Unfortunately, that does not work
The key to this problem is the file /usr/spool/lp/SCHEDLCK.
This file is simply a flag to indicate that the scheduler is running
and prevent it from being started again. If the scheduler has stopped
and won't restart, make sure that this file does not exist. If it
does, simply remove it.
On other occasions, none of these things fix your problem. It often
difficult to find the solution when you cannot see what is happening
at each step. Since the print spooler is run behind the scenes, you
rarely get a glimp of what it is doing. However, we can force the
system to tell us what it is doing with a simply little trick.
If you remember in chapter 3, I mentioned placing a set
-x in a script to have it display each command as it is
executed. Remember that this goes to stderr and not stdout. As the
print spooler is executing the interface script, there is no stderr
like from a script we start from the command line. So, instead of
displaying each line to the screen, the output is mailed to
you. There is a mail file for each print job that you submit. You can
then examine the mail files to figure out what is happening.
If you are using RLP to do remote printing there are a couple of
things to cover. If you submit a job that is destined to be printed
on a remote machine, but never arrives, the first place to look is
the local machine. First check to see if you can print at all from
the local machine. If not, it is unlikely that remote printing will
work. If you can print locally, make sure that the printer is enable
and accepting requests.
If the local printer is enabled and accepting requests, its still
possible for the problem to be local. Make sure that lpd
is running on both sides. The local side needs to be able to
send the file and the remote side needs to be able to accept the
file. For remote printing, there is also the rlpstat
command, which gives you information similar to lpstat.
Also check /usr/spool/lpd/<printer_name>/status.
This file gives you status information on the specific printer, which
is usually helpful in tracking down the problem.
The print scheduler itself, lpschedžhas
the ability to do it's own debugging. To enable debugging, you need
to start lpsched with the
-d option. This is easily
accomplished by editing the print scheduler start-up script in
S80lp). Note that this
option does exists in ODT, but it is not listed in the
Information is displayed to the screen when lpsched
starts up and other information is placed in files in
There will be three files of primary interested. The messages
file will contain all "messages" between lp
and lpsched. The requests
file will contain information on all request submitted. The
exec file contains
information on all commands executed by lpsched.
/etc/default/lpd - line printer daemon configuration file
/usr/bin/cancel - cancel print requests
/usr/bin/lp - The print program
/usr/bin/lprint - print program for local printing
/usr/bin/lpstat - status of print service
/usr/bin/rlpstat - status of remote print service
/usr/lib/lpadmin - configure the printers and print service
/usr/lib/lpmove - move print requests to a different printer