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