1# 2# Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3# Use is subject to license terms. 4# 5# CDDL HEADER START 6# 7# The contents of this file are subject to the terms of the 8# Common Development and Distribution License, Version 1.0 only 9# (the "License"). You may not use this file except in compliance 10# with the License. 11# 12# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 13# or http://www.opensolaris.org/os/licensing. 14# See the License for the specific language governing permissions 15# and limitations under the License. 16# 17# When distributing Covered Code, include this CDDL HEADER in each 18# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 19# If applicable, add the following below this CDDL HEADER, with the 20# fields enclosed by brackets "[]" replaced with your own identifying 21# information: Portions Copyright [yyyy] [name of copyright owner] 22# 23# CDDL HEADER END 24# 25########### 26## 27## Network Standard printer interface program. 28## 29########### 30 31##### 32# We can't do much except exit if spooler/scheduler 33# cancels us. 34##### 35trap 'eval exit_clean 15' 15 36 37#### 38# 39# Send standard error messages to /dev/null rather than to 40# the spooler. Avoids "Terminated" messages that shell puts out 41# when gets SIGTERM. Save standard error so it can be used 42# when we need it 43#### 44exec 5>&2 2>/dev/null 3>&1 45 46#### 47# set some global variables 48#### 49 50: ${LPTMPDIR:=/tmp} 51: ${SPOOLDIR:=/usr/spool/lp} 52: ${LOCALPATH:=${SPOOLDIR}/bin} 53PATH="/bin:/usr/bin:${LOCALPATH}" 54exit_code=0 55 56 57# ${LPTELL} is the name of a program that will send its 58# standard input to the Spooler. It is used to forward 59# the description of a printer fault to the Spooler, 60# which uses it in an alert to the administrator. 61##### 62if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ] 63then 64 fake_lptell () { 65 header="no" 66 while read line 67 do 68 if [ "no" = "${header}" ] 69 then 70 errmsg ERROR ${E_IP_UNKNOWN} \ 71 "unknown printer/interface failure" \ 72 "consult your system administrator; 73 reasons for failure (if any) follow:" 74 header=yes 75 fi 76 echo "${line}" >&2 77 done 78 return 1 79 } 80 LPTELL=fake_lptell 81fi 82 83##### 84# Error message formatter: 85# 86# Invoke as 87# 88# errmsg severity message-number problem help 89# 90# where severity is "ERROR" or "WARNING", message-number is 91# a unique identifier, problem is a short description of the 92# problem, and help is a short suggestion for fixing the problem. 93##### 94 95LP_ERR_LABEL="UX:lp" 96E_IP_ARGS=1 97E_IP_OPTS=2 98#E_IP_FILTER=3 99E_IP_UNKNOWN=5 100E_IP_BADFILE=6 101E_IP_ERRORS=12 # (in slow.filter) 102 103errmsg () { 104 105 case $1 in 106 ERROR ) 107 sev=" ERROR"; 108 ;; 109 WARNING ) 110 sev="WARNING"; 111 ;; 112 esac 113 114 echo "${LP_ERR_LABEL}:$2 ${sev}: $3 115 TO FIX: $4" >&5 116} 117 118########### 119## 120## Check arguments 121########### 122 123parse () { 124 echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`" 125} 126 127##### 128## 129## Error Cleanup and Exit 130## 131##### 132 133exit_clean() 134{ 135 136 if [ -f "${LPTMPDIR}/pr_eexit_code.$$" ] 137 then 138 /bin/rm ${LPTMPDIR}/pr_eexit_code.$$ 139 fi 140 141 if [ -f "${LPTMPDIR}/small_banner.$$" ] 142 then 143 /bin/rm ${LPTMPDIR}/small_banner.$$ 144 fi 145 146 if [ -f "${tmpfile}" ] 147 then 148 /bin/rm "${tmpfile}" 149 fi 150 151 exit $1 152} 153 154##### 155# 156# This program is invoked as 157# 158# ${SPOOLDIR}/.../printer request-id user title copies options files... 159# 160# The first three arguments are simply reprinted on the banner page, 161# the fourth (copies) is used to control the number of copies to print, 162# the fifth (options) is a blank separated list (in a single argument) 163# of user or Spooler supplied options (without the -o prefix), 164# and the last arguments are the files to print. 165##### 166 167if [ $# -lt 5 ] 168then 169 170 errmsg ERROR ${E_IP_ARGS} \ 171 "wrong number of arguments to interface program" \ 172 "consult your system administrator" 173 exit 1 174fi 175 176printer=`basename $0` 177request_id=$1 178user_name=$2 179title=$3 180copies=$4 181option_list=$5 182 183shift 5 184files="$*" 185 186 187# 188# debug sent to file if defined in /etc/syslog.conf 189# syslog.conf entry: 190# lpr.debug /path/filename 191# 192logger -p lpr.debug -t "netstandard: ${request_id}" " " 193logger -p lpr.debug -t "netstandard: ${request_id}" "INPUT" 194logger -p lpr.debug -t "netstandard: ${request_id}" " printer : ${printer}" 195logger -p lpr.debug -t "netstandard: ${request_id}" " request_id : ${request_id}" 196logger -p lpr.debug -t "netstandard: ${request_id}" " user_name : ${user_name}" 197logger -p lpr.debug -t "netstandard: ${request_id}" " title : ${title}" 198logger -p lpr.debug -t "netstandard: ${request_id}" " copies : ${copies}" 199logger -p lpr.debug -t "netstandard: ${request_id}" " option_list : ${option_list}" 200logger -p lpr.debug -t "netstandard: ${request_id}" " files : ${files}" 201logger -p lpr.debug -t "netstandard: ${request_id}" " spooler_key ${SPOOLER_KEY}" 202 203#### 204# default: do print a banner 205#### 206nobanner=no 207nofilebreak="no" 208inlist= 209data_file_flag= 210 211for i in ${option_list} 212do 213 case "${inlist}${i}" in 214 215 nobanner ) 216 nobanner="yes" 217 ;; 218 219 nofilebreak ) 220 nofilebreak="yes" 221 ;; 222 223 ##### 224 # 225 # If you want to add simple options (e.g. -o simple) 226 # identify them here. 227 ##### 228# simple ) 229# simple="yes" 230# ;; 231 232 cpi=pica ) 233 cpi=10 234 ;; 235 cpi=elite ) 236 cpi=12 237 ;; 238 cpi=* ) 239 cpi=`parse ${i}` 240 ;; 241 242 lpi=* ) 243 lpi=`parse ${i}` 244 ;; 245 246 length=* ) 247 length=`parse ${i}` 248 ;; 249 250 width=* ) 251 width=`parse ${i}` 252 ;; 253 dest=* ) 254 dest="-d `parse ${i}`" 255 ;; 256 257 protocol=* ) 258 protocol="-P `parse ${i}`" 259 ;; 260 bsdctrl=* ) 261 controlfile="-c `parse ${i}`" 262 ;; 263 timeout=* ) 264 timeout="-t `parse ${i}`" 265 ;; 266 267 data-file-type=* ) 268 data_file_flag="-f `parse ${i}`" 269 ;; 270 271 ##### 272 # 273 # If you want to add simple-value options (e.g. -o value=a) 274 # identify them here. 275 ##### 276# value=* ) 277# value=`parse ${i}` 278# ;; 279 280 ##### 281 # 282 # If you want to add options that, 283 # take a list (e.g. -o lopt='a b c'), identif 284 # them here and below (look for LOPT). 285 ##### 286 287# flist=* | lpd=* | options=* ) 288 flist=* | lpd=* ) 289#LOPT stty=* | flist=* | lpd=* | lopt=* ) 290 291 inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"` 292 case "${i}" in 293 ${inlist}\'*\' ) 294 item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"` 295 ;; 296 ${inlist}\' ) 297 continue 298 ;; 299 ${inlist}\'* ) 300 item=`expr "${i}" : "^[^=]*='*\(.*\)\$"` 301 ;; 302 ${inlist}* ) 303 item=`expr "${i}" : "^[^=]*=\(.*\)\$"` 304 ;; 305 *\' ) 306 item=`expr "${i}" : "^\(.*\)'\$"` 307 ;; 308 * ) 309 item="${i}" 310 ;; 311 esac 312 313 ##### 314 # 315 # We don't dare use "eval" because a clever user could 316 # put something in an option value that we'd end up 317 # exec'ing. 318 ##### 319 case "${inlist}" in 320 flist= ) 321 flist="${flist} ${item}" 322 ;; 323 lpd= ) 324 lpd="${lpd} ${item}" 325 ;; 326#LOPT lopt= ) 327#LOPT lopt="${lopt} ${item}" 328#LOPT ;; 329# options= ) 330# options="${options} ${item}" 331# ;; 332 esac 333 334 case "${i}" in 335 ${inlist}\'*\' ) 336 inlist= 337 ;; 338 ${inlist}\'* ) 339 ;; 340 *\' | ${inlist}* ) 341 inlist= 342 ;; 343 esac 344 ;; 345 346 * ) 347 errmsg WARNING ${E_IP_OPTS} \ 348 "unrecognized \"-o ${i}\" option" \ 349 "check the option, resubmit if necessary 350 printing continues" 351 ;; 352 esac 353done 354 355logger -p lpr.debug -t "netstandard: ${request_id}" "term : ${TERM}" 356 357if [ -z "${FILTER}" ] 358then 359 ##### 360 # 361 # If no filter is being used, we use netpr to push the 362 # file to the printer. 363 # (QUOTES ARE IMPORTANT!) 364 ##### 365 366 case "$TERM" in 367 PS ) 368 # make the "postscript" printers use netpr 369 FILTER= 370 ;; 371 PSR ) 372 # make the "reverse postscript" printers reverse the 373 # output and the use postio to talk to the printer 374 #FILTER="/usr/lib/lp/postscript/postreverse " 375 #FILTER= 376 FILTER="/usr/lib/lp/postscript/postreverse " 377 ;; 378 * ) 379 # We don't know the type, so just assume that the 380 # input and output are the same. Use netpr. 381 #FILTER=/bin/cat 382 FILTER= 383 ;; 384 esac 385fi 386 387#### 388# sets default value for ordering of data and control files with 389# bsd protocol. Default: data files first. Administrator 390# may set to control file first with lpadmin -o bsdctrl=first 391#### 392 393banner_flag="" 394case "${nobanner}" in 395 yes ) 396 banner_flag="-b" 397 ;; 398esac 399 400NETPR="/usr/lib/lp/bin/netpr ${banner_flag} ${data_file_flag} \ 401 -I ${request_id} -U ${user_name} \ 402 -p ${printer} ${dest} -T \"${title}\" \ 403 ${timeout} ${protocol} ${controlfile} " 404LPTELL_OPTS="-l" # netpr sends LaserWriter style messages back 405 406logger -p lpr.debug -t "netstandard: ${request_id}" "NETPR= ${NETPR}" 407logger -p lpr.debug -t "netstandard: ${request_id}" "filter : ${FILTER}" 408 409node=`uname -n` 410pid=$$ 411tmpfile=${LPTMPDIR}/${node}.${pid} 412 413logger -p lpr.debug -t "netstandard: ${request_id}" "tmpfile : ${tmpfile}" 414 415##### 416# 417# Set up filter for banner page 418# 419##### 420banner_filter= 421case "${TERM}" in 422PS | PSR ) 423 banner_filter=" | /usr/lib/lp/postscript/postprint " 424 LPTELL_OPTS="-l" 425 ;; 426esac 427 428##### 429# 430# Build temporary file that is the banner page 431# 432##### 433PAD="#####${NL}" 434CR="\r" 435NL="${CR}\n" 436FF= 437 438small_banner() { 439 echo "${CR}\c" 440 echo "${PAD}\c" 441 echo "##### User: ${user_name}${NL}\c" 442 if [ -n "${title}" ] 443 then 444 echo "##### Title: ${title}${NL}\c" 445 fi 446 echo "##### Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c" 447 echo "##### Job: ${request_id}${NL}\c" 448 echo "${PAD}\c" 449 if [ -n "${FF}" ] 450 then 451 echo "${CR}${FF}\c" 452 fi 453} 454 455##### 456# 457# Doing small banner as we don't know what printer is out there 458# 459##### 460banner=small_banner 461 462if [ "no" = "${nobanner}" ] 463then 464 eval "${banner} ${banner_filter}" 2>&1 1>${LPTMPDIR}/small_banner.$$ 465fi 466 467##### 468# 469# Print banner page before job unless PSR 470# 471##### 472 473 474if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" ] 475then 476 ( 477 eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1 478 echo $? > ${LPTMPDIR}/pr_eexit_code.$$ 479 ) | ${LPTELL} ${LPTELL_OPTS} ${printer} 480 481 exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` 482 logger -p lpr.debug -t "netstandard: ${request_id}" \ 483 "banner page exit code : ${exit_code}" 484 485fi 486 487i=1 488while [ $i -le $copies ] 489do 490 for file in ${files} 491 do 492 if [ -r "${file}" ] 493 then 494 495 if [ ! -z "${FILTER}" ] 496 then 497 ( 498 ##### 499 # There is a filter, use it 500 # 501 # Put 0<${file} before the "eval" to keep 502 # clever users from giving a file name that 503 # evaluates as something to execute. 504 # Redirect stderr to stdout so LPTELL will 505 # get error messages from pipe. 506 ##### 507 508 0<${file} eval ${FILTER} 2>&1 1>${tmpfile} 509 echo $? > ${LPTMPDIR}/pr_eexit_code.$$ 510 ) | ${LPTELL} ${LPTELL_OPTS} ${printer} 511 512 exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` 513 logger -p lpr.debug -t "netstandard: ${request_id}" \ 514 "filter exit_code : ${exit_code}" 515 516 if [ -n "${exit_code}" ] 517 then 518 if [ "${exit_code}" -eq 0 ] 519 then 520 printfile=${tmpfile} 521 else 522 #### 523 # The filter did not succeed, so don't try to print 524 #### 525 printfile= 526 fi 527 fi 528 529 else 530 printfile=${file} 531 fi 532 533 logger -p lpr.debug -t "netstandard: ${request_id}" \ 534 "printfile : ${printfile}" 535 536 ##### 537 # Print the file 538 ##### 539 540 if [ -r "${printfile}" ] 541 then 542 ( 543 eval ${NETPR} ${printfile} 2>&1 544 echo $? > ${LPTMPDIR}/pr_eexit_code.$$ 545 ) | ${LPTELL} ${LPTELL_OPTS} ${printer} 546 547 exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` 548 logger -p lpr.debug -t "netstandard: ${request_id}" \ 549 "netpr exit_code : ${exit_code}" 550 551 if [ -f "${tmpfile}" ] 552 then 553 /bin/rm "${tmpfile}" 554 fi 555 556 if [ -n "${exit_code}" ] 557 then 558 if [ "${exit_code}" -eq 0 ] 559 then 560 printone=yes 561 else 562 if [ "${exit_code}" -lt 128 ] 563 then 564 noprint=yes 565 else 566 retry=yes 567 fi 568 fi 569 fi 570 571 572 else 573 574 errmsg WARNING ${E_IP_BADFILE} \ 575 "cannot read temporary file \"${printfile}\""\ 576 "see if file still exists, 577 or consult your system administrator; 578 printing continues" 579 580 fi 581 else 582 583 ##### 584 # 585 # Don't complain about not being able to read 586 # a file on second and subsequent copies, unless 587 # we've not complained yet. This removes repeated 588 # messages about the same file yet reduces the 589 # chance that the user can remove a file and not 590 # know that we had trouble finding it. 591 ##### 592 593 if [ "${i}" -le 1 -o -z "${badfileyet}" ] 594 then 595 errmsg WARNING ${E_IP_BADFILE} \ 596 "cannot read file \"${file}\"" \ 597 "see if the file still exists and is readable, 598 or consult your system administrator; 599 printing continues" 600 badfileyet=yes 601 fi 602 603 fi 604 605# for file in ${files} 606 done 607 i=`expr $i + 1` 608done 609 610##### 611# 612# If printing in reverse order, print the banner page now 613# 614##### 615 616if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ] 617then 618( 619 eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1 620 echo $? > ${LPTMPDIR}/pr_eexit_code.$$ 621) | ${LPTELL} ${LPTELL_OPTS} ${printer} 622fi 623 624exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` 625logger -p lpr.debug -t "netstandard: ${request_id}" \ 626 "banner page exit code : ${exit_code}" 627 628if [ -n "${printone}" -a -z "${retry}" -a -z "${noprint}" ] 629then 630 exit_code=`expr 0` 631else 632 if [ -n "${retry}" -a -z "${printone}" -a -z "${noprint}" ] 633 then 634 exit_code=`expr 129` 635 else 636 exit_code=`expr 1` 637 fi 638fi 639 640logger -p lpr.debug -t "netstandard: ${request_id}" \ 641 "FINAL exit_code : ${exit_code}" 642 643exit_clean ${exit_code} 644