|
Set up a print server with SolarisFind out how to print multiple content types with lpadmin -- a proven methodology
|
Setting up a print server that handles multiple content types may not seem like a difficult task -- and it isn't, as long as third-party software figures into the equation. The difficulties arise when you decide to go strictly with lpadmin. Unix sysadmins Errol Fouquet and Robert Krumm guide you through this process with a proven methodology for setting up a print server that can successfully handle plain text, PostScript, and printable binary (pcl, rtl) content types. (2,900 words)
Mail this article to a friend |
We run Zeh Graphic Systems's ZPS plotting software on a Sun Ultra Enterprise 450 supporting several applications that output many graphic formats. We also support LPD from a few other applications, and user printing from Netscape, as well as user printing at the command line. The print clients in our environment are mostly Sun servers and workstations numbering close to 200. We also have one Windows NT server running Citrix Winframe, which is also a print client.
Apart from applications, which plot through Zeh, and, therefore, use our Ultra 450 as a spooler, all other print requests are transmitted from the client directly to the network printer. Functionally, this works fine, printing all the content types we need, including text, PostScript, and printable binary (pcl and rtl). The problem is that the setup is an administration nightmare. Often, a huge, unacceptable binary file, like a GIF or JPEG, would be printing out reams of garbage, and we would have no easily available method of determining the source of the request. We would know only that a workstation or server somewhere in the building was sending a bad job to the printer. Unfortunately, banner pages weren't an option, as the user community didn't want to waste paper (ironic, huh?).
We did manage to write a shell script that would rsh over to all the machines in the building and report the activity to a given printer. With this information we could execute the Cancel command. But this was horribly slow and inefficient.
The customer's own technical-computing strategy indicated that the solution was to implement a print server for the Unix environment, but it failed to offer details for this configuration. In addition, a recent NOMAN (network operations management) assessment, conducted by Sprint Paranet, also identified implementing a print server to meet the customer's printing needs.
We knew that a print server was the right solution, and if we could just set it up, all print requests could be managed from a single machine, greatly simplifying the entire process. As it turned out this wound up being much more difficult than we anticipated.
Attempt 1: Trial and error
Initially, we wanted to set up standard Solaris print spooling. We
designated a test machine, called nolsn099 (an Ultra-1 running Solaris
2.6), as the test print server, and we began several tests. The printer
we began testing with was an HP 1600c, called no1316p in our NIS/DNS
environment.
After each server setup, the client machine (an Ultra-1 running Solaris
2.5.1) was set up to access the printer/plotter with the command
lpadmin -p no1316p -s nolsn099!no1316p
Server setup 1 | lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T PS \ -I PostScript -v /dev/null -i /usr/lib/lp/model/netstandard |
Result: Client machine was able to print PostScript and binary (pcl, rtl) files fine, but text files would staircase. | |
Server setup 2 | lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T unknown \ -I any -v /dev/null -i /usr/lib/lp/model/netstandard |
Result: Client machine was able to print text files fine, but PostScript, rtl, and pcl files printed garbage. | |
Server setup 3 |
lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T PS -I text \ -v /dev/null -i /usr/lib/lp/model/netstandard |
Result: Client machine was able to print text and PostScript files fine, but rtl and pcl files printed garbage. | |
Server setup 4 |
lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T unknown \ -I PostScript,text,simple -v /dev/null \ -i /usr/lib/lp/model/netstandard lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T unknown \ -I any,PostScript,simple -v /dev/null \ -i /usr/lib/lp/model/netstandard lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T PS \ -I any -v /dev/null -i /usr/lib/lp/model/netstandard lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T unknown \ -I text,simple -v /dev/null -i /usr/lib/lp/model/netstandard lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T hplaser \ -I text,simple -v /dev/null -i /usr/lib/lp/model/netstandard |
Result: All of these resulted in client being able to print PostScript, pcl, and rtl, but the text files would staircase. | |
Server setup 5 |
lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T PS \ -I any -v /dev/null -i /usr/lib/lp/model/netstandard |
Result: This allowed for PostScript and text files to be printed fine, but this printed garbage for pcl and rtl files. |
As you can see, we tried several combinations, but were unsuccessful in
printing all three desired formats. The man page for lpadmin suggests
that you also can have a list for the -T option. We decided that what
we really needed was a -T unknown,PS
option, but
unfortunately, lpadmin doesn't allow "unknown" to be coupled with any
other terminfo type.
We concluded that with the standard options available to Solaris lpadmin, we would only be able to set up a printer to handle:
Our next step was to log a call with Sun's software support. We were fortunate to get a very helpful support person on the phone, who gave us what seemed to be a solution. Although he admitted that it was something of a hack, he was sure that it would work. The solution involved setting up two queues for each printer on the print server and then employing double spooling. The first device would function as a filter and then pipe its output to the network printer. (We decided to adopt a convention of creating a printername and a printername-r for each device we configured, so we have a no1316p and a no1316p-r.)
When we first set this up, it seemed like a winner. The dos2unix command fixed the staircasing of text files, and we were able to print PostScript, pcl, and rtl files. We were almost ready to celebrate when we noticed that the quality of the pcl and rtl files was extremely poor. The dos2unix command was corrupting the binary format!
We got back on the phone with Sun. This time we set up a conference call with several Sun engineers to report our needs and findings. They suggested using an lpadmin command (one we'd already tried) to set up the printer. When we told them how this caused the text files to staircase, two of the engineers groaned knowingly. They promised to investigate. In the meantime, we resumed our own quest to find a solution.
|
|
|
|
Attempt 2: Red tape
Next, we tried using Hewlett-Packard's JetAdmin software, Sun's recommended
solution for network printing to HPs. We set up a test machine to use as a print
server, then set up the JetAdmin software. It worked great. We were
able to print all three file types without error. We were able to set up
clients to spool through this server fine, and the software gave us the
information we needed to manage unwanted jobs. We had found our
solution! Wrong. We were told that replacing the XCD cards was not an
option.
We still hadn't heard back from Sun, so we chose to revisit the "double spooling" solution.
Attempt 3: Double spooling revisited
We decided that double spooling had brought us too close to abandon it
completely. Only the limitations of unix2dos stood in the way of
success. If we could examine the input file and execute only the
unix2dos on nonbinary files, we would have our solution. We wrote a
simple Perl script (unix2dos.pl) to do just that:
#!/opt/bin/perl # open standard input open(FOO, "-"); # test if binary if ( -B FOO) { while (<FOO>) { print $_; } } # if not binary.. perform unix2dos filtering else { while (<FOO>) { s/\n/\r\n/; print; } } close(FOO);
We then replaced the line in the interface file as follows:
FILTER=/opt/utils/unix2dos.pl | lp -s -d no1316p-r
That clinched it. We were able to print all three formats without any
problems. Or at least that's what we thought. Unfortunately, because of
the double spooling, the print jobs in the no1316p-r queue no longer
had meaningful names or owners. For example, when a client printed a
file, like /etc/passwd, and we executed lpq -Pno1316p
on
the print server, we would see something like this:
$ lpq -Pno1316p Rank Owner Job File(s) Total Size active dlister 313 /etc/passwd 522 bytes
But after no1316p filtered the job and piped it to lp -s -dno1316p-r
,
and we executed lpq -Pno1316p-r
on the
server, we'd see something like this:
$ lpq -Pno1316p-r Rank Owner Job File(s) Total Size active lp 1629 1629-1 536 bytes
Without properly designated filenames and owners, users couldn't track their files in the print queue, and we couldn't delete jobs from the queue upon request.
So we contacted Sun support again. We sent a detailed e-mail to our account rep, copying the two engineers from the conference call, and explaining the progress we had made and how this new obstacle was posing a real problem to print management. The response we got in return was a bit discouraging, to say the least: "This mail describes one of the many reasons that we don't recommend or support double spooling and/or requeueing jobs."
We were on our own.
Attempt 4: Finding a compromise
Because we were successful in spooling all three file types, the last
thing we needed was meaningful lpq info for our network printer queue.
We knew that when the print job was queued through the filtering queue
(no1316p, for instance), the original filename and user name was
available. We had to figure out a way of preserving this information
and associating it with the job queued on the actual network printer
queue (no1316p-r, for instance).
We knew that when a job was sent through the filtering queue, the lp
subsystem would return the information we were interested in. So it
stood to reason that we should be able to harness this info from
environment variables. As it turns out, the variable we were
interested in can be harnessed in the interface script of the filtering
queue: ${request_id}
,
${user_name}
,${files}
, and
${flist}
. But we still faced the problem of associating
this information with the lpq of the actual network printer queue.
What we needed was a means of logging the requests coming into the
filtering queue, and a method of mapping entries in the network printer
queue back to the original information.
The strategy we eventually adopted filtered the input to a temporary
file, which had the original ${request_id}
in the name.
We then piped to an lp of this temporary file. The lpq info of the
network printer queue now included the original
${request_id}
in the form of the filename. That left only
the log file. We further modified the interface script of the
filtering queue to include the following logic immediately before the
if [ -z "${FILTER}" ]
:
# write current request_id user_name and flist to logfile # if the flist variable is null, we are printing a single file, # therefore echo ${files} # else echo ${flist} if [ "$flist" = "" ]; then echo "${request_id} ${user_name} ${files}" \ $gt; $gt; /var/spool/lp/save_dir/logs/request.log else echo "${request_id} ${user_name} ${flist}" \ $gt; $gt; /var/spool/lp/save_dir/logs/request.log fi
We incorporated the creation of the temporary file into the unix2dos.pl script shown earlier. The new script is called lp.pl:
#!/opt/bin/perl # open standard input open(FOO, "-"); # create temp file for writing open(OUT, ">/var/spool/lp/save_dir/tmp/$ARGV[0].$$"); # if input stream is binary do not filter if ( -B FOO) { while () { print OUT $_; } } # else filter the line unix2dos style else { while ( ) { s/\n/\r\n/; print OUT; } } close(FOO); close(OUT); # send print request system("/bin/lp -s -d $ARGV[1] /var/spool/lp/save_dir/tmp/$ARGV[0].$$");
Next, we passed lp.pl two arguments: ${request_id}
, and
network printer
. The script then created a filtered
temporary file named ${request_id}."pid of process"
and
executed an lp of this temporary file.
Then, we replaced the line in the interface script of filtering queue that read
FILTER=/opt/utils/unix2dos.pl | lp -s -d no1316p-r
with
FILTER="/var/spool/lp/save_dir/sbin/lp.pl ${request_id} no1316p-r"
Let's take a break and summarize what's happening up to this point:
lp -d no1316p /var/adm/messages
At this point, if we perform an lpq on the network printer, the output will look something like this:
$ lpq -Pno1316p-r Rank Owner Job File(s) Total Size active lp 1629 /var/spool/lp/save_dir/tmp/no1316p-1625.2974 536 bytes
Now, all we need is a script that will index into our log file, find no1316p-1625, and return the original owner and filename. To serve this need we wrote lpq.ksh:
#!/bin/ksh typeset -i N typeset -i N2 # set N2 equal to the default number of fields per log file entry N2=3 if [ $# -ne 1 ] then echo "usage: $0 network_printer_queue" exit 1 fi echo "Rank Owner Job File(s) Total Size" /usr/ucb/lpq -P $1 | grep bytes | while read line do RANK=`echo $line | awk '{print $1}'` JOB=`echo $line | awk '{print $3}'` SIZE=`echo $line | awk '{print $5}'` TEMP=`echo $line | awk '{print $4}'` GREPSTUFF=`basename $TEMP | awk -F. '{print $1}'` OWNER=`grep -w $GREPSTUFF /var/spool/lp/save_dir/logs/request.log \ | awk '{print $2}'` # count the number of fields in the log file: 3 means a single file # printed more than # 3 means that several files were sent at once. N=`grep -w $GREPSTUFF /var/spool/lp/save_dir/logs/request.log \ | awk '{print NF}'` if [ $N -gt 3 ]; then FILE=`grep -w $GREPSTUFF /var/spool/lp/save_dir/logs/request.log \ | awk "{print \\$$N2}"` echo "$RANK $OWNER $JOB $FILE $SIZE bytes" N2=N2+1; else N2=3 FILE=`grep -w $GREPSTUFF /var/spool/lp/save_dir/logs/request.log \ | awk '{print $3}'` echo "$RANK $OWNER $JOB $FILE $SIZE bytes" fi done
This script takes a single argument: the name of the network printer
queue. In our scenario, we simply enter $ lpq.ksh no1316p-r
to display
the following output:
Rank Owner Job File(s) Total Size active dlister 1629 /var/adm/messages 536 bytes
Using this script, we were able to give our end users the information they needed to track their print jobs, and the printing support staff could better manage jobs on the print server.
Cleanup
Finally, we needed some means of deleting the temporary files we were
creating in /var/spool/lp/save_dir/tmp. I noticed that once a job
had successfully completed through the lp subsystem, an
entry, in the form of T filename
, appeared in the file /var/spool/lp/logs/requests.
To clean up these temp files up we wrote a script called cleanup.ksh:
#!/bin/ksh cd /var/spool/lp/save_dir/tmp unalias ls # our temp files are all begin with "no" if [ -f no* ]; then for i in `ls no*` do grep "^T $i" /var/spool/lp/logs/requests > /dev/null 2>&1 if [ $? -eq 0 ]; then rm -f $i fi done fi
We set up a cron job on the print server to run this script once every hour.
Conclusion
While we admit that this solution could use further refinement, we
accomplished what we set out to do:
In addition, we believe that the modifications described in this article could be incorporated into the printing subsystem of Solaris 2.6, eliminating the need for third-party software and hardware solutions. Sun would simply need to add a native filter for the lp subsystem, which provides the logic of our handy unix2dos Perl script, to eliminate the double spooling (officially unsupported by Sun) we are doing now.
|
Resources
About the author
Errol Fouquet
is a certified Solaris Administrator and all around Unix
bigot employed with Sprint Paranet. When not "putting out fires" at
work, he can be found roaming around New Orleans with his lovely wife
Kristin.
|
Robert Krumm is currently employed as a Technical Analyst for Sprint Paranet. Being a Certified Network Administrator, Microsoft Certified Professional, and currently Site Leader at his customer site, Robert has supported Solaris for over 2 1/2 years and supports the Zeh Plotting software. |
If you have technical problems with this magazine, contact webmaster@sunworld.com
URL: http://www.sunworld.com/swol-04-1999/swol-04-printserver.html
Last modified: