Well we *finally* got LPRng all set up at our site. And now that the
kinks have been (mostly) worked out, it's running very nicely.
(Converting over from our several-years-old LPRng installation was a
pain!)
Some of what we did might be useful to a few people, so I'm going to
share some of our scripts and such that we used to customize the
setup, mostly ifhp issues. To provide some context, our site is a
couple hundred machines (workstations and servers, mostly Solaris)
that send print jobs to a single central print server. The printers
are mostly networked HP's (and one pesky SparcPrinter E, ack!). We
also run SAMBA so that PC's and other machines not on our main network
can send jobs to our printers. We are currently running LPRng-3.7.4
and ifhp-3.4.4.
[Note: If you notice that we went to trouble to implement things that
are supported by built-in LPRng and/or ifhp features, please let me
know.]
To start with, we are using the file conversion features in ifhp.conf
to intelligently handle most print jobs. One problem we noticed was
that "unknown" print jobs were quietly discarded (a config option?).
In order to send an email back to the user to notify them that their
job had failed, we designated a2ps as a "filter", and supplied a
wrapper script (attached) for a2ps. If a2ps fails (in the conversion),
then the wrapper returns some binary junk and a successful return
code, the file_util command returns "data", and our "oddjob.sh" script
(attached) is invoked. (Is there more direct support for this sort of
thing in ifhp?)
# excerpt from ifhp.conf
file_output_match = [
*gzip_compressed* filter \%s{gzip_decompress}
*compress*data* filter \%s{gzip_decompress}
*pdf* ps \%s{pdf_converter}
*postscript* ps \%s{ps_converter}
*tex_dvi* ps \%s{dvi_converter}
*ascii_text* pcl \%s{text_converter}
*pcl* pcl \%s{pcl_converter}
data pcl \%s{unknown_converter}
*pjl* pjl \%s{pjl_converter}
*printer*job*language* pjl \%s{pjl_converter}
* filter \%s{a2ps_converter}
]
a2ps_options= -q -B -1 -M \%M{papersize} --borders=no -o-
a2ps_converter= /auto/global/lprng/libexec/filters/a2ps-wrapper.sh \%s{a2ps_options}
pdf_converter= /auto/global/lprng/libexec/filters/acroread-wrapper.sh
dvi_converter= /auto/global/lprng/libexec/filters/dvips-wrapper.sh
unknown_converter= /auto/global/lprng/libexec/filters/oddjob.sh \%s{ARGV}
gzip_decompress = /usr/local/bin/gunzip -c
ps_converter=
pcl_converter=
pjl_converter=
text_converter=
Acroread (for PDF conversions) on our (Solaris) system leaves its data
files in /tmp (ie, it doesn't clean up), so to get around this, we
made it a special case and provided a wrapper (attached).
DVI conversions also seem to be problematic due to I/O expectations,
so yet another wrapper (attached) was added for appropriate I/O
support. (dvips did not seem to work properly thru a2ps.)
Another problem was that our printcap contains client and server
entries, and this seemed to confuse SAMBA (were we doing something
wrong?). So we added a filter (attached) (to be run by hand) that
will convert our unified printcap file into an abbreviated version
that SAMBA can digest. Certain assumptions are builtin, but the
script could be enhanced.
Also, we do some informational printer accounting. The accounting.sh
sample script supplied with ifhp seems very inefficient, since it has
to call external programs to parse each command line option. So we
wrote a perl version (attached) which also deals with an ifhp bug
(repeated options).
Lastly, I've included our PJL/PCL banner script (perl).
If anyone else has any interesting ways to handle these or other
issues, I'd appreciate seeing them posted to this list.
Regards,
-Dan
--
Daniel E. Singer, System Administrator
Dept. of Computer Science, Duke University, Durham NC 27708 USA
[EMAIL PROTECTED], www.cs.duke.edu/~des, (919)660-6577
#!/bin/sh
# @(#) /auto/global/lprng/libexec/filters/SCCS/s.a2ps-wrapper.sh 1.1 2001/02/02
13:21:57
#
# a2ps-wrapper.sh: set the path(s) so that it can find stuff;
# a2ps is called by the ifhp filter, but some of this stuff
# might not be set the way we want;
#
# this will be used as a "filter"; if the data it a type that a2ps
# cannot handle, then just return some junk binary data so that ifhp
# will process it a unknown "data".
#
# 1/2001, D.Singer
a2ps='/usr/local/bin/a2ps'
# this is just some junk binary data, might be trouble to try to print...
BIN_STRING=""
PATH='/usr/local/bin:/usr/prop/bin:/usr/bin:/usr/ucb:/usr/sbin:/usr/ccs/bin:/etc'
LD_LIBRARY_PATH='/usr/local/lib:/usr/lib:/usr/openwin/lib:/usr/local/X/lib:/usr/local/X11R5/lib:/usr/dt/lib:/usr/ucblib'
export PATH LD_LIBRARY_PATH
#exec $a2ps "$@"
#echo "a2ps-wrapper.sh: could not exec a2ps." >&2
#exit 3
$a2ps "$@" || cat "/auto/global/lprng/etc/data.bin"
exit
#!/bin/sh
# @(#) /auto/global/lprng/libexec/filters/SCCS/s.oddjob.sh 1.1 2001/02/02
13:22:45
#
# oddjob.sh: email or print a message for a job that otherwise could not
# be converted/printed
#
# 1/2001, D.Singer
PATH='/usr/local/bin:/usr/prop/bin:/usr/bin:/usr/ucb:/usr/sbin:/usr/ccs/bin:/etc'
LD_LIBRARY_PATH='/usr/local/lib:/usr/lib:/usr/openwin/lib:/usr/local/X/lib:/usr/local/X11R5/lib:/usr/dt/lib:/usr/ucblib'
export PATH LD_LIBRARY_PATH
SMAIL='/usr/lib/sendmail -t'
FROM='[EMAIL PROTECTED]'
PROBS_TO='[EMAIL PROTECTED]'
REPLY_TO='[EMAIL PROTECTED]'
CC=
BCC='[EMAIL PROTECTED]'
#
# prepare a printable option list before the options get messed up
#
optstr=
for opt do
case "$opt" in
-*|acct)
optstr="$optstr
$opt"
;;
*)
optstr="$optstr $opt"
esac
done
host=
job=
jobno=
queue=
time=
user=
#
# process options
#
while [ $# != 0 ]; do
case "$1" in
-f*)
job=`/usr/bin/expr "$1" : '..\(.*\)'`
;;
-h*)
host=`/usr/bin/expr "$1" : '..\(.*\)'`
;;
-j*)
jobno=`/usr/bin/expr "$1" : '..\(.*\)'`
;;
-n*)
user=`/usr/bin/expr "$1" : '..\(.*\)'`
;;
-Q*)
queue=`/usr/bin/expr "$1" : '..\(.*\)'`
;;
-t*)
time=`/usr/bin/expr "$1" : '..\(.*\)'`
esac
shift
done
# this should go to status file?
echo "oddjob.sh: processing job $jobno for user $user." >&2
#
# dump any standard input
# (maybe not necessary?)
#
cat > /dev/null
#
# try to get more info about the user from NIS
#
got_user=
if [ -n "$user" ]; then
if pw_line=`/usr/bin/ypmatch "$user" passwd.byname 2>&-` ; then
set -f
_IFS="$IFS"
IFS=":"
set -- $pw_line
IFS="$_IFS"
set +f
full_name="$5"
got_user=1
fi
fi
#
# if we have determined a user, send the report via email;
# otherwise, send it to the printer;
#
if [ "$got_user" ]; then
echo "\
From: Duke C.S. Printing System <$FROM>
Organization: Duke University Department of Computer Science
To: $full_name <${user}@cs.duke.edu>${CC:+
Cc: $CC}${BCC:+
Bcc: $BCC}${REPLY_TO:+
Reply-To: $REPLY_TO}
Subject: Your print job could not be printed
The following job could not be printed due to an unsupported data format:
User: $user
Job: $job
Queue: $queue
Job#: $jobno
Host: $host
Time: $time
If you believe that there is a problem with the printing system
(and not your job), please forward this e-mail along with your
explanation to <$PROBS_TO>.
Full options list:
$optstr" |
$SMAIL
else
echo "
(s3BThe following job could not be printed due to an unsupported data format:
(s1B
User: $user
Job: $job
Queue: $queue
Job#: $jobno
Host: $host
Time: $time
(s0B
If you believe that there is a problem with the printing system
(and not your job), please send e-mail with appropriate details
to <$PROBS_TO>.
Full options list:
$optstr"
fi
exit 0
#!/bin/sh
# @(#) /auto/global/lprng/libexec/filters/SCCS/s.acroread-wrapper.sh 1.1
2001/02/02 13:22:22
#
# acroread-wrapper.sh: acroread leaves randomly named copies of the PDF files
# in /tmp, so this is a way around that;
#
# 1/2001, D.Singer
acroread='/usr/local/bin/acroread -toPostScript'
tmpdir='/var/tmp'
tmpfile="acroread.$$"
# remove the two temporary files
trap 'rm -f "$tmpfile.pdf" "$tmpfile.ps"' 0 1 2 3 9 13 15
PATH='/usr/local/bin:/usr/prop/bin:/usr/bin:/usr/ucb:/usr/sbin:/usr/ccs/bin:/etc'
LD_LIBRARY_PATH='/usr/local/lib:/usr/lib:/usr/openwin/lib:/usr/local/X/lib:/usr/local/X11R5/lib:/usr/dt/lib:/usr/ucblib'
export PATH LD_LIBRARY_PATH
# go to the tmp dir
cd "$tmpdir"
# dump stdin to a file
cat > "$tmpfile.pdf"
# convert the file; this will create file.ps
$acroread "$tmpfile.pdf" || {
echo "acroread-wrapper.sh: problem running acroread." >&2
exit 3
}
# copy the PS file to stdout
cat < "$tmpfile.ps"
exit 0
#!/bin/sh
# @(#) /auto/global/lprng/libexec/filters/SCCS/s.dvips-wrapper.sh 1.1 2001/02/02
13:22:33
#
# dvips-wrapper.sh: dvips requires a filename argument
#
# 1/2001, D.Singer
dvips='/usr/local/bin/dvips'
tmpdir='/var/tmp'
tmpfile="dvips.$$"
# remove the two temporary files
trap 'rm -f "$tmpfile.dvi" "$tmpfile.ps"' 0 1 2 3 9 13 15
PATH='/usr/local/bin:/usr/prop/bin:/usr/bin:/usr/ucb:/usr/sbin:/usr/ccs/bin:/etc'
LD_LIBRARY_PATH='/usr/local/lib:/usr/lib:/usr/openwin/lib:/usr/local/X/lib:/usr/local/X11R5/lib:/usr/dt/lib:/usr/ucblib'
export PATH LD_LIBRARY_PATH
# go to the tmp dir
cd "$tmpdir"
# dump stdin to a file
cat > "$tmpfile.dvi"
# convert the file; this will create file.ps
$dvips "$tmpfile.dvi" || {
echo "dvips-wrapper.sh: problem running dvips." >&2
exit 3
}
# copy the PS file to stdout
cat < "$tmpfile.ps"
exit 0
#!/bin/sh
# printcap_samba_filter: make a printcap that SAMBA can digest;
# use as a filter:
# this_script < some_file > some_other_file
#
# certain assumptions are made here about the printcap format
# which may be more restrictive than what lprng allows;
# (ie, if printcap is reworked, this script could break)
# also, for now, the printserver hostname is hardcoded in,
# instead of being more intelligently extracted from the
# printcap data; (I'm avoiding putting too much work into
# this, since a more direct means of support may yet be
# uncovered, or maybe we'll eventually go back to separate
# client and server printcaps, in which case samba probably
# won't need this)
#
# 1/2001, D.Singer
#PRINTSERVER_HOST="gutenberg"
PRINTSERVER_HOST="printserver"
AWK=awk
SYS=`uname -sr`
case "$SYS" in
'SunOS '*)
AWK=nawk
esac
# for testing
#cat printcap |
$AWK -v "PS_HOST=$PRINTSERVER_HOST" -v "DATE=`date`" '{
if ($1 ~ /^#/) {
if (VERS == "" && $0 ~ /\@\(\#\)/)
VERS = $0;
next;
}
if (NF == 0) {
IN_ENTRY = 0;
next;
}
if ($0 ~ /^[ \t]/) {
if (!IN_ENTRY)
next;
add_to_entry($0);
}
else {
if (IN_ENTRY)
finish_entry();
start_entry($0);
IN_ENTRY = 1;
}
}
func start_entry(line) {
if (line ~ /^all:/)
return;
LCNT = 0;
N = split(line,NN,"|");
CUR_ENT = NN[1];
ELINES[0] = line;
if (CUR_ENT !~ /^[a-zA-Z0-9]/)
ETYPE = "INCLUDE";
#print CUR_ENT;
}
func finish_entry() {
if (ETYPE != "SERVER") {
NLIST[CUR_ENT] = ++ECNT;
ELIST[ECNT] = CUR_ENT;
for (I=0; I+0 <= LCNT; ++I)
ENT_LINES[ECNT,I] = ELINES[I];
ENT_LCNT[ECNT] = LCNT;
ENT_TYPE[ECNT] = ETYPE;
}
}
#func delete_entry(entry) {
# NLIST[entry] = 0;
#}
func add_to_entry(line) {
ELINES[++LCNT] = line;
if (line ~ /:client/)
ETYPE = "CLIENT";
else if (line ~ /:server/)
ETYPE = "SERVER";
}
func add_include(num) {
ELINES[++LCNT] = line;
if (line ~ /:client/)
ETYPE = "CLIENT";
else if (line ~ /:server/)
ETYPE = "SERVER";
}
END {
if (IN_ENTRY)
finish_entry();
print "# printcap file generated for SAMBA, " DATE;
if (VERS != "") {
print "# based on this printcap version:";
print VERS;
}
print "";
for (I=1; I+0 <= ECNT; ++I) {
N = split(ENT_LINES[I,0],EE,"|");
if (EE[1] !~ /^[a-zA-Z0-9]/)
continue;
for (J=1; J+0 <= N; ++J)
print EE[J] ":lp=" EE[J] "@" PS_HOST;
}
}'
exit
#!/usr/local/bin/perl
# @(#) /auto/global/lprng/libexec/filters/SCCS/s.acc.pl 1.1 2001/02/02 13:21:23
#
# acc.pl, 11/2000, D.Singer
# derived from:
#
# Patrick Powell Sun Sep 3 11:23:22 PDT 1995
# LPRng
#= File: =
#= accounting.sh =
#= =
#= Synopsis: =
#This program is called at the completion of printing a job by the OF
#filter. The accounting file will hold information about the
#completion of a job. The accounting file will have the following
#format:
#
#start -qpid -kcontrolfile -nlogin -hhost -Pprinter \
# -ppagecounter -Fformt -Ttime
#end -bpages -qpid -kcontrolfile -nlogin -hhost -Pprinter \
# -ppagecounter -Ffmt -Ttime
#
#The accounting program will be called with the following parameters
#
#program -bpages -qpid -kcontrolfile \
# -nlogin -hhost -Pprinter -ppagecounter -Fformt '-Ttime' accoutingfile
#$file1 = "/var/spool/lprng/PRINTER_ACCOUNTING_LOG";
$file1 = "/var/spool/lpd/ACCT_LOG";
#$file2 = "/auto/global/lprng/log/acct_log";
$file2 = "/auto/global/lprng/log/acct_log";
$debugfile = "/auto/global/lprng/log/acct_log.debug";
$debug = 0;
$pages = "";
$pid = "";
$controlfile = "";
$login = "";
$host = "";
$printer = "";
$pagecounter = "";
$format = "";
$time = "";
$accountingfile = "";
$mode = "";
$zoption = "";
foreach ( @ARGV ) {
if (($mode eq "") and (/^start$/ or /^end$/)) {
$mode = $_;
}
elsif (/^-b/) {
$pages = substr($_,2) if ($pages eq "");
}
elsif (/^-h/) {
if ($host eq "") {
$host = substr($_,2);
$host =~ s/\.cs\.duke\.edu$//;
}
}
elsif (/^-k/) {
$controlfile = substr($_,2) if ($controlfile eq "");
}
elsif (/^-n/) {
$login = substr($_,2) if ($login eq "");
}
elsif (/^-p/) {
$pagecounter = substr($_,2) if ($pagecounter eq "");
}
elsif (/^-q/) {
$pid = substr($_,2) if ($pid eq "");
}
elsif (/^-t/) {
$time = substr($_,2) if ($time eq "");
}
elsif (/^-F/) {
$format = substr($_,2) if ($format eq "");
}
elsif (/^-P/) {
$printer = substr($_,2) if ($printer eq "");
}
elsif (/^-Z/) {
$zoption = substr($_,2) if ($zoption eq "");
}
elsif (/^-/) {
}
else {
$accountingfile = $_;
#last;
}
}
$line =
"ifhp|$login|$pid|$host|$printer|$format|$zoption|$pagecounter|$pages|$time\n";
if ($mode eq "start") {
exit 0;
}
if ($debug) {
open FH, ">>$debugfile" or die "cannot open \"$debugfile\".";
print FH "\n";
foreach ( @ARGV ) {
print FH "$_\n";
}
print FH "mode = $mode\n";
print FH "accountingfile = $accountingfile\n";
close FH;
#exit 0;
}
#elsif ($mode eq "start") {
# exit 0;
#}
if ($file1 ne "") {
open FH, ">>$file1" or die "cannot open \"$file1\".";
print FH $line;
close FH;
}
if ($file2 ne "") {
open FH, ">>$file2" or die "cannot open \"$file2\".";
print FH $line;
close FH;
}
exit 0;
#!/usr/local/bin/perl5
# @(#) /auto/global/lprng/libexec/filters/SCCS/s.csbanner 1.1 2001/02/02 13:24:16
#
# csbanner - banner program to use with LPRng
# (note: was ysbanner)
# Duke C.S. dept.
#
# Notes: The first version of this (written by Yuji?) expected arguments
# on STDIN; this version, based on a later version of LPRng, expects arguments
# on the command line, as per other LPRng programs. Many modifications
# were made by D.Singer, 9/2000.
#
# $debug = 1;
use Getopt::Std;
#use File::Basename;
BEGIN{
$xpos = 0;
$ypos = 0;
$incr = 0;
#
# PCL and PJL stuff
#
$UEL = "\033%-12345X";
$UELPJL = "\033%-12345X\@PJL \r\n";
$PCLRESETSTR = "\033E";
$CRLFSTR = "\033&k2G";
$SIMPLEX = "\033&l0S";
$DUPLEX = "\033&l1S";
$margins = "\033&l0u0Z";
#$darkbar = "\033*c1800a100b45g2P";
#$lightbar = "\033*c1800a100b25g2P";
$fontchange = "\033(8U\033(s1p%dv0s0b4148T" ;
$position = "\033*p%dx%dY";
}
sub moveto {
($x,$y) = @_;
printf $position, $x, $y;
}
sub fontsize {
($size) = @_;
$incr = ($size * 300 * 1.1) / 72;
printf $fontchange, $size;
}
# print out a bar, and adjust the vertical position
sub dobar {
# width, height, darkness
my($_w,$_h,$_d) = @_;
#&moveto( $xpos, $ypos );
# eg, "\033*c2400a50b30g2P"
printf "\033*c%sa%sb%sg2P", $_w, $_h, $_d;
$ypos += $_h;
}
# print out a bar, and adjust the vertical position
sub dobox {
# width, height, thickness, darkness
my($_w,$_h,$_t,$_d) = @_;
my $_hx = $xpos; my $_hy = $ypos;
&moveto( $_hx, $_hy );
dobar $_w, $_t, $_d;
&moveto( $_hx, $_hy+$_t );
dobar $_t, ($_h - ($_t * 2)), $_d;
&moveto( $_hx+($_w-$_t), $_hy+$_t );
dobar $_t, ($_h - ($_t * 2)), $_d;
&moveto( $_hx, $_hy+($_h-$_t) );
dobar $_w, $_t, $_d;
$xpos = $_hx;
$ypos = $_hy + $_h;
}
# (don't know why this is called outline...)
sub outline {
($s) = @_;
printf "%s", $s;
}
# print keyword and value, with specified positioning for the value (0 for none)
sub argline {
($key,$value,$tab) = @_;
$holdxpos = $xpos;
&moveto( $xpos, $ypos );
printf "%s", $key;
if ($tab != 0) {
$xpos += $tab;
&moveto( $xpos, $ypos );
}
printf "%s", $value;
$ypos += $incr;
$xpos = $holdxpos;
}
#sub argline {
# ($key,$value) = @_;
# &textline( $key , 1, 0 );
# &textline( $value, 0, 1 );
#}
#
#sub textline{
# ( $line, $start, $end ) = @_;
# if ($start) {
# &moveto( $xpos, $ypos );
# }
# printf "%s", $line;
# if( $end ){
# $ypos += $incr;
# }
#}
sub convdate {
my $date;
($date) = @_;
if ($date =~ /(\d\d\d\d)-(\d\d)-(\d\d)-(\d\d):(\d\d):(\d\d)/) {
$yr = $1;
$mo = $2;
$day = $3;
$hr = $4;
$min = $5;
$sec = $6;
@y = split(//,$yr);
$yr = join('',@y[2,3]);
$date = "$mo/$day/$yr $hr:$min:$sec";
}
$date;
}
#
# print out the banner page
#
sub pcl_banner(){
&outline($UEL);
&outline($PCLRESETSTR);
&outline($UELPJL);
&outline($CRLFSTR);
&outline($SIMPLEX);
&outline($margins);
#$xpos = 0; $ypos = 0;
# do top bar
#&moveto( $xpos, $ypos );
#&dobar(2400,20,15);
#&moveto( $xpos, $ypos );
#&dobar(2400,40,30);
#&moveto( $xpos, $ypos );
#&dobar(2400,20,15);
$xpos = 0; $ypos = 0;
&moveto( $xpos, $ypos );
&dobox(2400,600,20,15);
$xpos = 20; $ypos = 20;
&moveto( $xpos, $ypos );
&dobox(2360,560,40,30);
$xpos = 60; $ypos = 60;
&moveto( $xpos, $ypos );
&dobox(2280,480,20,15);
$xpos = 120; $ypos = 120;
&moveto( $xpos, $ypos );
# set font size
#&fontsize( 28 );
&fontsize( 24 );
$ypos += $incr;
&moveto( $xpos, $ypos );
&argline("User: ",$data{"User"},300);
# smaller font
&fontsize( 18 );
#&argline("Host: ",$data{"Host"},300);
&argline("Job: ",$data{"Job"},300);
$ypos += $incr * .4;
$date = &convdate($data{"Date"},300);
&argline("Date: ",$date,300);
$ypos -= $incr / 3;
# do bottom bar
#&moveto( $xpos, $ypos );
#&dobar(2400,20,15);
#&moveto( $xpos, $ypos );
#&dobar(2400,40,30);
#&moveto( $xpos, $ypos );
#&dobar(2400,20,15);
$xpos = 120; $ypos += 100;
&moveto( $xpos, $ypos );
# smaller font
&fontsize( 10 );
$ypos += 100 + $incr*2;
&moveto( $xpos, $ypos );
# print out all of the job data
for $key (sort keys %data) {
&argline("$key: ",$data{$key},0)
}
# bar test
#$ypos += 100;
#for ($i=5; $i <=100; $i+=5) {
# &dobar(2400,25,$i);
#}
&outline($FFEED);
&outline($UEL);
&outline($PCLRESETSTR);
}
MAIN: {
# print STDERR "ARGV:".join(" ",@ARGV)."\n";
# pcl_banner();
#while(<STDIN>) {
# print if ($debug);
# chop;
# @args = split(/(\w+\\: )/);
# if ($debug) {
# print "ARGS:\r\n".join("\r\n",@args);
# }
# for $p (@args) {
# next if ($p =~ /^\s*$/);
# if ($p =~ /\\: $/) {
# $label = $`;
# } else {
# $data{$label} = $p;
# }
# }
# if ($debug) {
# print "\r\n";
# print "DATA:\r\n";
# for $k (keys %data) {
# print "$k ==> [$data{$k}]\r\n";
# }
# }
#}
# process command line options
for $a (@ARGV) {
#&argline("\nArg: ", $a, 0 );
next if ($a !~ /^-./);
$opts{substr($a,1,1)} = substr($a,2);
}
# grab the ones we're interested in
$data{'Job-ID'} = $opts{'A'} if (defined($opts{'A'}));
$data{'Class'} = $opts{'C'} if (defined($opts{'C'}));
$data{'Job'} = $opts{'J'} if (defined($opts{'J'}));
$data{'Printer'} = $opts{'P'} if (defined($opts{'P'}));
$data{'Queue'} = $opts{'Q'} if (defined($opts{'Q'}));
$data{'Desc'} = $opts{'S'} if (defined($opts{'S'}));
$data{'SizeKB'} = $opts{'b'} if (defined($opts{'b'}));
$data{'Host'} = $opts{'h'} if (defined($opts{'h'}));
$data{'Job-No'} = $opts{'j'} if (defined($opts{'j'}));
$data{'User'} = $opts{'n'} if (defined($opts{'n'}));
$data{'Date'} = $opts{'t'} if (defined($opts{'t'}));
$data{'Z-Opts'} = $opts{'Z'} if (defined($opts{'Z'}));
# print the banner page
&pcl_banner();
exit(0);
}
# EOF