Copyright 1996-1998 by James Mohr. All rights reserved. Used by permission of the author.
Be sure to visit Jim's great Linux Tutorial web site at http://www.linux-tutorial.info/
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 do.
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.
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 directory.
Once the jobs are printed, these files are removed and the information they contain is combined and placed in the "request log" (/usr/spool/lp/logs/requests). 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.
Content of line
Number of copies
Destination. Either a printer or a class of printers (more on that later)
Name 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.
Form name used (if one is specified). (More on forms later.)
Special handling, such as resume, hold or immediate
Notification. When the job is finished, should the user get an email message or have a message written to the terminal.
Options given to lp with -o.
Priority of the print job (if applicable).
List of pages printed.
Raw processing options (if any) given to lp
Character set or print wheel used
Success of the job, expressed as a combination of bits in hex form:
0x0004 Slow filtering finished successfully.
0x0010 Printing finished successfully.
0x0040 Request was canceled.
0x0100 Request failed filtering or printing.
Title on the banner page.
Type of file content
User who submitted the print job.
Special modes to give to the filters. Fast filter
Printer 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.
Table 0.1 Contents of Printer Spooler Working and Log Files
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 lpstat(C) man-page when you get a chance.
When I run lpstat -t on my system, I get:
scheduler is running
system default destination: DeskJet
device for DeskJet: /dev/lp0
device for Panasonic: /dev/lp1
DeskJet accepting requests since Tue May 23 20:07:37 1995
Panasonic accepting requests since Fri May 26 16:16:54 1995
printer DeskJet is idle. enabled since Fri May 26 16:00:05 1995. available.
printer Panasonic is idle. enabled since Fri May 26 16:16:54 1995. available.
DeskJet-7 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 /usr/spool/lp/admins/lp/printer/<printer_name> where <printer_name> 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 /usr/spool/lp/system/pstatus.: 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 friend lpstat.
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 in:
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 on hold:
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 /usr/spool/lp/temp/42-0 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 anyway.
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 lower priority.
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 command.
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 being printed.
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 to /usr/spool/lp/admins/lp/interfaces 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 landscape.)
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 simple.
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 /usr/spool/lp/admins/lp/interfaces directory by hand. Instead make a copy in the /usr/spool/lp/model 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 characteristic.
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
case $i in
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 add.
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.
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 -d printer_name"
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 work,
) | $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 /usr/spool/lp/remote file. 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.
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 actual printing.
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 /usr/bin into /usr/lpd/remote and 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 distribution media.
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/lpd/remote and /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 we take a quick look on one of my machines:
# Remote Line Printer (BSD format)
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 not local. 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 more.
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.
Figure 0-2 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 theoretically possible.
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
plain: 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 /usr/spool/lp/remote. 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.
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 no modifications.
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:
/usr/lib/lpadmin -p DeskJet -m HPDeskJet -o nobanner -v /dev/lp0
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) man-page.
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 /etc/rc.d/8/userdef. Since 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 either.
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 /etc/rc2.d (probably S80lp). Note that this option does exists in ODT, but it is not listed in the lpsched(ADM) man-page. Information is displayed to the screen when lpsched starts up and other information is placed in files in /usr/spool/lp/logs.
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.
Table 0.2 Key print spooler files
Copyright 1996-1998 by James Mohr. All rights reserved. Used by permission of the author.
Be sure to visit Jim's great Linux Tutorial web site at http://www.linux-tutorial.info/