# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" ########### ## ## Network Standard printer interface program. ## ########### ##### # We can't do much except exit if spooler/scheduler # cancels us. ##### trap 'eval exit_clean 15' 15 #### # # Send standard error messages to /dev/null rather than to # the spooler. Avoids "Terminated" messages that shell puts out # when gets SIGTERM. Save standard error so it can be used # when we need it #### exec 5>&2 2>/dev/null 3>&1 #### # set some global variables #### : ${LPTMPDIR:=/tmp} : ${SPOOLDIR:=/usr/spool/lp} : ${LOCALPATH:=${SPOOLDIR}/bin} PATH="/bin:/usr/bin:${LOCALPATH}" exit_code=0 # ${LPTELL} is the name of a program that will send its # standard input to the Spooler. It is used to forward # the description of a printer fault to the Spooler, # which uses it in an alert to the administrator. ##### if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ] then fake_lptell () { header="no" while read line do if [ "no" = "${header}" ] then errmsg ERROR ${E_IP_UNKNOWN} \ "unknown printer/interface failure" \ "consult your system administrator; reasons for failure (if any) follow:" header=yes fi echo "${line}" >&2 done return 1 } LPTELL=fake_lptell fi ##### # ${LPTSOLSEPARATOR} is the name of a program to put banner and trailer # pages around the job. ##### if [ -x ${LOCALPATH}/lp.tsol_separator ] then LPTSOLSEPARATOR=${LOCALPATH}/lp.tsol_separator else echo "${LOCALPATH}/lp.tsol_separator not found." >&2 exit 1 fi ##### # Error message formatter: # # Invoke as # # errmsg severity message-number problem help # # where severity is "ERROR" or "WARNING", message-number is # a unique identifier, problem is a short description of the # problem, and help is a short suggestion for fixing the problem. ##### LP_ERR_LABEL="UX:lp" E_IP_ARGS=1 E_IP_OPTS=2 #E_IP_FILTER=3 E_IP_UNKNOWN=5 E_IP_BADFILE=6 E_IP_ERRORS=12 # (in slow.filter) errmsg () { case $1 in ERROR ) sev=" ERROR"; ;; WARNING ) sev="WARNING"; ;; esac echo "${LP_ERR_LABEL}:$2 ${sev}: $3 TO FIX: $4" >&5 } ########### ## ## Check arguments ########### parse () { echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`" } ##### ## ## Error Cleanup and Exit ## ##### exit_clean() { if [ -f "${LPTMPDIR}/pr_eexit_code.$$" ] then /bin/rm ${LPTMPDIR}/pr_eexit_code.$$ fi if [ -f "${LPTMPDIR}/small_banner.$$" ] then /bin/rm ${LPTMPDIR}/small_banner.$$ fi if [ -f "${LPTMPDIR}/banner.exit_code.$$" ] then /bin/rm ${LPTMPDIR}/banner.exit_code.$$ fi if [ -f "${LPTMPDIR}/banner.errmsg.$$" ] then /bin/rm ${LPTMPDIR}/banner.errmsg.$$ fi if [ -f "${tmpfile}" ] then /bin/rm "${tmpfile}" fi exit $1 } ##### # # This program is invoked as # # ${SPOOLDIR}/.../printer request-id user title copies options files... # # The first three arguments are simply reprinted on the banner page, # the fourth (copies) is used to control the number of copies to print, # the fifth (options) is a blank separated list (in a single argument) # of user or Spooler supplied options (without the -o prefix), # and the last arguments are the files to print. ##### if [ $# -lt 5 ] then errmsg ERROR ${E_IP_ARGS} \ "wrong number of arguments to interface program" \ "consult your system administrator" exit 1 fi printer=`basename $0` request_id=$1 user_name=$2 title=$3 copies=$4 option_list=$5 shift 5 files="$*" # # debug sent to file if defined in /etc/syslog.conf # syslog.conf entry: # lpr.debug /path/filename # logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " " logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "INPUT" logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \ printer : ${printer}" logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \ request_id : ${request_id}" logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \ user_name : ${user_name}" logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " title : ${title}" logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \ copies : ${copies}" logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \ option_list : ${option_list}" logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " files : ${files}" logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \ spooler_key ${SPOOLER_KEY}" #### # default: do print a banner #### nobanner=no nolabels="no" nofilebreak="no" inlist= data_file_flag= for i in ${option_list} do case "${inlist}${i}" in nobanner ) nobanner="yes" ;; nofilebreak ) nofilebreak="yes" ;; nolabels ) nolabels="yes" ;; ##### # # If you want to add simple options (e.g. -o simple) # identify them here. ##### # simple ) # simple="yes" # ;; cpi=pica ) cpi=10 ;; cpi=elite ) cpi=12 ;; cpi=* ) cpi=`parse ${i}` ;; lpi=* ) lpi=`parse ${i}` ;; length=* ) length=`parse ${i}` ;; width=* ) width=`parse ${i}` ;; dest=* ) dest="-d `parse ${i}`" ;; protocol=* ) protocol="-P `parse ${i}`" ;; bsdctrl=* ) controlfile="-c `parse ${i}`" ;; timeout=* ) timeout="-t `parse ${i}`" ;; data-file-type=* ) data_file_flag="-f `parse ${i}`" ;; ##### # # If you want to add simple-value options (e.g. -o value=a) # identify them here. ##### # value=* ) # value=`parse ${i}` # ;; ##### # # If you want to add options that, # take a list (e.g. -o lopt='a b c'), identif # them here and below (look for LOPT). ##### # flist=* | lpd=* | options=* ) flist=* | lpd=* ) #LOPT stty=* | flist=* | lpd=* | lopt=* ) inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"` case "${i}" in ${inlist}\'*\' ) item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"` ;; ${inlist}\' ) continue ;; ${inlist}\'* ) item=`expr "${i}" : "^[^=]*='*\(.*\)\$"` ;; ${inlist}* ) item=`expr "${i}" : "^[^=]*=\(.*\)\$"` ;; *\' ) item=`expr "${i}" : "^\(.*\)'\$"` ;; * ) item="${i}" ;; esac ##### # # We don't dare use "eval" because a clever user could # put something in an option value that we'd end up # exec'ing. ##### case "${inlist}" in flist= ) flist="${flist} ${item}" ;; lpd= ) lpd="${lpd} ${item}" ;; #LOPT lopt= ) #LOPT lopt="${lopt} ${item}" #LOPT ;; # options= ) # options="${options} ${item}" # ;; esac case "${i}" in ${inlist}\'*\' ) inlist= ;; ${inlist}\'* ) ;; *\' | ${inlist}* ) inlist= ;; esac ;; * ) errmsg WARNING ${E_IP_OPTS} \ "unrecognized \"-o ${i}\" option" \ "check the option, resubmit if necessary printing continues" ;; esac done logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "term : ${TERM}" if [ -z "${FILTER}" ] then ##### # # If no filter is being used, we use netpr to push the # file to the printer. # (QUOTES ARE IMPORTANT!) ##### case "$TERM" in PS ) # make the "postscript" printers use cat # (TSOL banners are added during filtering, so we have # to use some filter.) FILTER=/bin/cat ;; PSR ) # make the "reverse postscript" printers reverse the # output and the use postio to talk to the printer #FILTER="/usr/lib/lp/postscript/postreverse " #FILTER= FILTER="/usr/lib/lp/postscript/postreverse " ;; * ) # We don't know the type, so just assume that the # input and output are the same. Use netpr. #FILTER=/bin/cat FILTER= ;; esac fi #### # sets default value for ordering of data and control files with # bsd protocol. Default: data files first. Administrator # may set to control file first with lpadmin -o bsdctrl=first #### banner_flag="" case "${nobanner}" in yes ) banner_flag="-b" ;; esac NETPR="/usr/lib/lp/bin/netpr ${banner_flag} ${data_file_flag} \ -I ${request_id} -U ${user_name} \ -p ${printer} ${dest} -T \"${title}\" \ ${timeout} ${protocol} ${controlfile} " LPTELL_OPTS="-l" # netpr sends LaserWriter style messages back logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "NETPR= ${NETPR}" logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "filter : ${FILTER}" node=`uname -n` pid=$$ tmpfile=${LPTMPDIR}/${node}.${pid} logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "tmpfile : ${tmpfile}" ##### # # Set up filter for banner page # ##### banner_filter= case "${TERM}" in PS | PSR ) banner_filter=" | /usr/lib/lp/postscript/postprint " LPTELL_OPTS="-l" ;; esac ##### # # Build temporary file that is the banner page # ##### PAD="#####${NL}" CR="\r" NL="${CR}\n" FF= small_banner() { echo "${CR}\c" echo "${PAD}\c" echo "##### User: ${user_name}${NL}\c" if [ -n "${title}" ] then echo "##### Title: ${title}${NL}\c" fi echo "##### Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c" echo "##### Job: ${request_id}${NL}\c" echo "${PAD}\c" if [ -n "${FF}" ] then echo "${CR}${FF}\c" fi } ##### # # Doing small banner as we don't know what printer is out there # ##### banner=small_banner ## Skip this for PS/PSR printers, since lp.tsol_separator handles the banners if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ] then eval "${banner} ${banner_filter}" 2>&1 1>${LPTMPDIR}/small_banner.$$ fi ########### ## ## Surround the job by PostScript code to produce banner ## and trailerpages and page headers and footers. ## ########### BANNER_EXIT_CODE=${LPTMPDIR}/banner.exit_code.$$ echo 0 > ${BANNER_EXIT_CODE} TSOLSEPARATOR_LOG=${LPTMPDIR}/banner.errmsg.$$ tsol_bannerize () { TSOLSEPARATOR_OPTS="-e ${TSOLSEPARATOR_LOG}" if [ "yes" = "${nolabels}" ] then TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -l" fi if [ "yes" = "${nobanner}" ] then TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -t /dev/null -b /dev/null" fi if [ "${TERM}" = "PSR" ] then TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -r" fi # Get rid of the #, TAB and NL characters in the title tsol_title=`echo $title` tsol_title=`echo $tsol_title | sed 's/#//g'` logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \ "banner command: ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} \ ${printer} ${request_id} ${user_name} \"${tsol_title}\" ${file}" ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} ${printer} \ ${request_id} ${user_name} "${tsol_title}" ${file} echo $? > ${BANNER_EXIT_CODE} true } bannerize=tsol_bannerize if [ "yes" = "${nobanner}" -a "yes" = "${nolabels}" ] then bannerize=cat fi if [ "${TERM}" != "PSR" -a "${TERM}" != "PS" ] then bannerize=cat fi ##### # # Print banner page before job unless PS or PSR. # ##### if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ] then ( eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1 echo $? > ${LPTMPDIR}/pr_eexit_code.$$ ) | ${LPTELL} ${LPTELL_OPTS} ${printer} exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \ "banner page exit code : ${exit_code}" fi i=1 while [ $i -le $copies ] do for file in ${files} do if [ -r "${file}" ] then if [ ! -z "${FILTER}" ] then ( ##### # There is a filter, use it # # Put 0<${file} before the "eval" to keep # clever users from giving a file name that # evaluates as something to execute. # Redirect stderr to stdout so LPTELL will # get error messages from pipe. ##### 0<${file} $bannerize | eval ${FILTER} 2>&1 1>${tmpfile} echo $? > ${LPTMPDIR}/pr_eexit_code.$$ ) | ${LPTELL} ${LPTELL_OPTS} ${printer} # if lp.tsol_separator had an error, send its logged # error message to LPTELL. banner_exit_code=`cat ${BANNER_EXIT_CODE}` if [ -n "${banner_exit_code}" -a \ 0 -ne "${banner_exit_code}" -a \ -n "${LPTELL}" -a \ -r "${TSOLSEPARATOR_LOG}" ] then cat ${TSOLSEPARATOR_LOG} | ${LPTELL} ${printer} echo 77 > ${LPTMPDIR}/pr_eexit_code fi exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` logger -p lpr.debug \ -t "tsol_netstandard: ${request_id}" \ "filter exit_code : ${exit_code}" if [ -n "${exit_code}" ] then if [ "${exit_code}" -eq 0 ] then printfile=${tmpfile} else #### # The filter did not succeed, so don't try to print #### printfile= fi fi else printfile=${file} fi logger -p lpr.debug \ -t "tsol_netstandard: ${request_id}" \ "printfile : ${printfile}" ##### # Print the file ##### if [ -r "${printfile}" ] then ( eval ${NETPR} ${printfile} 2>&1 echo $? > ${LPTMPDIR}/pr_eexit_code.$$ ) | ${LPTELL} ${LPTELL_OPTS} ${printer} exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` logger -p lpr.debug \ -t "tsol_netstandard: ${request_id}" \ "netpr exit_code : ${exit_code}" # if [ -f "${tmpfile}" ] # then # /bin/rm "${tmpfile}" # fi if [ -n "${exit_code}" ] then if [ "${exit_code}" -eq 0 ] then printone=yes else if [ "${exit_code}" -lt 128 ] then noprint=yes else retry=yes fi fi fi else errmsg WARNING ${E_IP_BADFILE} \ "cannot read temporary file \"${printfile}\""\ "see if file still exists, or consult your system administrator; printing continues" fi else ##### # # Don't complain about not being able to read # a file on second and subsequent copies, unless # we've not complained yet. This removes repeated # messages about the same file yet reduces the # chance that the user can remove a file and not # know that we had trouble finding it. ##### if [ "${i}" -le 1 -o -z "${badfileyet}" ] then errmsg WARNING ${E_IP_BADFILE} \ "cannot read file \"${file}\"" \ "see if the file still exists and is readable, or consult your system administrator; printing continues" badfileyet=yes fi fi # for file in ${files} done i=`expr $i + 1` done ##### # # If printing in reverse order, print the banner page now # Skip this for TSOL, since lp.tsol_separator handles the banners # ##### # # if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ] # then # ( # eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1 # echo $? > ${LPTMPDIR}/pr_eexit_code.$$ # ) | ${LPTELL} ${LPTELL_OPTS} ${printer} # fi exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \ "banner page exit code : ${exit_code}" if [ -n "${printone}" -a -z "${retry}" -a -z "${noprint}" ] then exit_code=`expr 0` else if [ -n "${retry}" -a -z "${printone}" -a -z "${noprint}" ] then exit_code=`expr 129` else exit_code=`expr 1` fi fi logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \ "FINAL exit_code : ${exit_code}" exit_clean ${exit_code}