xref: /illumos-gate/usr/src/cmd/lp/model/tsol_netstandard (revision dbed73cbda2229fd1aa6dc5743993cae7f0a7ee9)
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