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