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