# # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (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 # ########### ## ## 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 ##### # 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 "${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 "netstandard: ${request_id}" " " logger -p lpr.debug -t "netstandard: ${request_id}" "INPUT" logger -p lpr.debug -t "netstandard: ${request_id}" " printer : ${printer}" logger -p lpr.debug -t "netstandard: ${request_id}" " request_id : ${request_id}" logger -p lpr.debug -t "netstandard: ${request_id}" " user_name : ${user_name}" logger -p lpr.debug -t "netstandard: ${request_id}" " title : ${title}" logger -p lpr.debug -t "netstandard: ${request_id}" " copies : ${copies}" logger -p lpr.debug -t "netstandard: ${request_id}" " option_list : ${option_list}" logger -p lpr.debug -t "netstandard: ${request_id}" " files : ${files}" logger -p lpr.debug -t "netstandard: ${request_id}" " spooler_key ${SPOOLER_KEY}" #### # default: do print a banner #### nobanner=no nofilebreak="no" inlist= data_file_flag= for i in ${option_list} do case "${inlist}${i}" in nobanner ) nobanner="yes" ;; nofilebreak ) nofilebreak="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 "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 netpr FILTER= ;; 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 "netstandard: ${request_id}" "NETPR= ${NETPR}" logger -p lpr.debug -t "netstandard: ${request_id}" "filter : ${FILTER}" node=`uname -n` pid=$$ tmpfile=${LPTMPDIR}/${node}.${pid} logger -p lpr.debug -t "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 if [ "no" = "${nobanner}" ] then eval "${banner} ${banner_filter}" 2>&1 1>${LPTMPDIR}/small_banner.$$ fi ##### # # Print banner page before job unless PSR # ##### if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" ] 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 "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} eval ${FILTER} 2>&1 1>${tmpfile} echo $? > ${LPTMPDIR}/pr_eexit_code.$$ ) | ${LPTELL} ${LPTELL_OPTS} ${printer} exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` logger -p lpr.debug -t "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 "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 "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 # ##### 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 "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 "netstandard: ${request_id}" \ "FINAL exit_code : ${exit_code}" exit_clean ${exit_code}