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