xref: /illumos-gate/usr/src/cmd/print/scripts/lpadmin (revision bcdabfc47e027d458c65d1c456642dd12908e197)
1#!/bin/ksh
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22#
23# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26#
27set -o noclobber
28
29PATH=/bin:/usr/bin:/usr/sbin export PATH
30
31TEXTDOMAIN="SUNW_OST_OSCMD"
32export TEXTDOMAIN
33
34PFEXEC=/usr/bin/pfexec
35LPSET=/usr/bin/lpset
36LPGET=/usr/bin/lpget
37LPSTAT=/usr/bin/lpstat
38LPADMIN=/usr/lib/lp/local/lpadmin
39LPFILTER=/usr/sbin/lpfilter
40COMM=/usr/bin/comm
41PPDMGR=/usr/sbin/ppdmgr
42
43HOST=$(/bin/uname -n)
44exit_code=0
45
46usage() {
47	gettext "Usage:\n" 1>&2
48	gettext "	lpadmin -p (printer) (options)\n" 1>&2
49	gettext "	lpadmin -x (dest)\n" 1>&2
50	gettext "	lpadmin -d (dest)\n" 1>&2
51	gettext "	lpadmin -S print-wheel -A alert-type [ -W minutes ]\n" 1>&2
52	gettext "		[ -Q requests ]\n" 1>&2
53	gettext "	lpadmin -M -f form-name [ -a [ -o filebreak ]\n" 1>&2
54	gettext "		[ -t tray-number ]]\n" 1>&2
55	exit 1
56}
57
58# create a filter table for LP service
59lp_config_filters() {
60	if [[ ! -f /etc/lp/filter.table ]] ; then
61		cd /etc/lp/fd ; for filter in *.fd ; do
62			${PFEXEC} ${LPFILTER} \
63				-f $(/usr/bin/basename $filter .fd) \
64				-F $filter
65		done
66	fi
67}
68
69# enable/disable LP related service(s)
70lp_config_service() {	# (enable | disable)
71	svcadm ${1} -s svc:/application/print/server:default
72	# svcadm ${1} -s svc:/application/print/rfc1179:default
73	# svcadm ${1} -s svc:/application/print/ipp-listener:default
74}
75
76# synchronize printers.conf with LP configuration changes
77lp_config_sync_pconf() {	# (pre) (post)
78	ADDED=$(${COMM} -13 ${1} ${2})
79	REMOVED=$(${COMM} -23 ${1} ${2})
80
81	lp_server=${server:-${HOST}}
82	for DEST in ${ADDED} ; do
83		lp_uri="ipp://${lp_server}/printers/${DEST}"
84		lp_bsdaddr="${lp_server},${DEST},Solaris"
85		${LPSET} -n system \
86			-a "printer-uri-supported=${lp_uri}" \
87			-a "bsdaddr=${lp_bsdaddr}" \
88		 	${DEST} 2>/dev/null
89	done
90
91	for DEST in ${REMOVED} ; do
92		${LPSET} -n system -x ${DEST} 2>/dev/null
93	done
94}
95
96# Delete all destinations in printers.conf
97delete_all() {
98	for DEST in $(lpget -n system list | egrep -e '.+:$' | sed -e 's/://')
99	do
100		${LPSET} -n system -x ${DEST}
101		status=$?
102	done
103}
104
105# Call the ppdmgr utility to add a new PPD file to the system.
106#
107# $1  - path to PPD file
108# $2  - label name (optional)
109add_new_ppd_file() {
110	# Add new ppd file and echo full path it was actually saved to
111	ppdmgrcmd="${PFEXEC} ${PPDMGR} -a ${1} -w"
112
113	ppderrfile=/tmp/lpadminerror.$$
114	ppd_file=$(${ppdmgrcmd} 2>${ppderrfile})
115	ppdmgrrc=$?
116	if [[ -s "${ppderrfile}" ]] ; then
117		print -n "lpadmin: " 1>&2
118		cat ${ppderrfile} 1>&2
119		rm -f ${ppderrfile} >/dev/null 2>&1
120		if [[ ${ppdmgrrc} -ne 0 ]] ; then
121			exit 1
122		fi
123	fi
124	rm -f ${ppderrfile} >/dev/null 2>&1
125}
126
127#
128# Execution begins here
129#
130
131# be sure that we can run lpset and lpget
132if [[ ! -x ${LPSET} || ! -x ${LPGET} ]] ; then
133	gettext "lpadmin: System error; cannot set default printer\n" 1>&2
134	exit 2
135fi
136
137if [[ $# -lt 1 ]] ; then
138	usage
139	exit 1
140fi
141
142# Deal with the -d option independently since getopts does not handle
143# options that may or may not have arguments
144#
145if [[ ${1} = "-d" ]] ; then
146	if [[ $# -eq 1 ]] ; then	# remove the "default"
147		${LPGET} -n system _default >/dev/null 2>&1
148		exit_code=$?
149
150		if [[ ${exit_code} -eq 0 ]] ; then
151			${LPSET} -n system -x _default
152			exit_code=$?
153		else	# no default, nothing to do
154			exit_code=0
155		fi
156	elif [[ $# -eq 2 ]] ; then	# add/change the "default"
157		${LPGET} -k bsdaddr ${2} >/dev/null 2>&1
158		exit_code=$?
159
160		if [[ $exit_code -eq 0 ]] ; then
161			${LPSET} -n system -a "use=${2}" _default
162			exit_code=$?
163		else	# can't set default to an unconfigured printer
164			gettext "${2}: undefined printer\n" 1>&1
165		fi
166	else				# invalid usage
167		usage
168		exit 1
169	fi
170
171	exit ${exit_code}
172fi
173
174#		Strip off legal options
175while getopts "A:ac:D:e:f:F:H:hi:I:lm:Mn:o:p:Q:r:S:s:T:u:U:v:W:x:t:P:" arg
176do
177	case $arg in
178	D)
179		description="${OPTARG}"
180	;;
181	n)
182		ppd_file="${OPTARG}"
183	;;
184	p)
185		if [[ -n "${delete}" ]] ; then
186			usage
187		fi
188		printer=${OPTARG}
189	;;
190	s)
191		server=${OPTARG}
192	;;
193	v|U)
194		device=${OPTARG}
195		if [[ ! -n "${server}" ]] ; then
196			server=${HOST}
197		fi
198		local="true"
199	;;
200	x)
201		if [[ -n "${printer}" || -n "${server}" || \
202		     -n "${device}" || -n "${description}" ]] ; then
203			usage
204		fi
205		delete=${OPTARG}
206		printer=${OPTARG}
207		if [[ ${printer} = "all" ]] ; then
208			local="true"
209		fi
210	;;
211	S|M|A)
212		local="true"
213	;;
214	c)
215		class=${OPTARG}
216		local="true"
217		if [[ ! -f ${LPGET} ]] ; then
218			gettext "lpadmin: System error; cannot set class\n " 1>&2
219			exit 2
220		fi
221
222		${LPGET} "${class}" > /dev/null 2>&1
223		lpget_class=$?
224		if [[ ${lpget_class} -eq 0 && ! -r /etc/lp/classes/"${class}" ]] ; then
225			gettext "lpadmin: ERROR: Can't create class ${class}.\n" 1>&2
226			gettext "           TO FIX: This is an existing printer name;\n" 1>&2
227			gettext "                   choose another name.\n" 1>&2
228			exit 1
229		fi
230	;;
231	r)
232		local="true"
233	;;
234	esac
235done
236
237#
238# We don't have anything to do; let user know and bail
239#
240if [[ ! -n "${printer}" && ! -n "${delete}" && ! -n "${local}" ]] ; then
241	gettext "lpadmin: ERROR: Nothing to do.\n" 1>&2
242	gettext "        TO FIX: You must give one of these options:\n" 1>&2
243	gettext "		      -p, -d, -x -S\n" 1>&2
244	exit 1
245fi
246
247#
248#       Printer does not exist
249#       To be consistent with 2.5, assume adding local printer
250#
251if [[ ! -n "${device}" && ! -n "${server}" && ! -n "${delete}" && \
252	  ! -n "${local}" ]] ; then
253	${LPGET} "${printer}" > /dev/null 2>&1
254	lpget_stat=$?
255	if [[ ${lpget_stat} -ne 0 ]] ; then
256		gettext "lpadmin: ERROR: Missing -U or -v option.\n" 1>&2
257		gettext "           TO FIX: Local printers must have\n" 1>&2
258		gettext "                   a port defined (-v option) or\n" 1>&2
259		gettext "                   have dial-out instructions (-U option).\n" 1>&2
260		exit 1
261	fi
262fi
263
264#	process the "server" value
265#	It can be a hostname, UUCP form (server!queue), RCMD form(queue@server),
266#	or in URI form ({scheme}://{endpoint})
267#
268case "${server}" in
269	*://*)	# URI form
270		uri=${server}
271		rem_printer=$(expr "${server}" : ".*://.*/\([^/]*\)")
272		server=$(expr "${server}" : ".*://\([^/]*\)/.*")
273		;;
274	*@*)	# RCMD form
275		rem_printer=$(expr "${server}" : "\(.*\)@.*")
276		server=$(expr "${server}" : ".*@\(.*\)")
277		;;
278	*!*)	# UUCP form
279		rem_printer=$(expr "${server}" : ".*!\(.*\)")
280		server=$(expr "${server}" : "\(.*\)!.*")
281		;;
282	*)	# hostname
283		rem_printer=${printer}
284		;;
285esac
286
287# if there is a "device" or LP configuration, it's local
288if [[ -n "${device}" || -f /etc/lp/printers/${printer}/configuration || \
289      -f /etc/lp/classes/${printer} ]] ; then
290	local="true"
291fi
292
293# Do the LP configuration for a local printer served by lpsched
294if [[ -x ${LPADMIN} && -n "${local}" ]] ; then
295	# enumerate LP configured printers before modification
296	PRE=/tmp/lpadmin-pre.$$
297	(/bin/ls /etc/lp/printers 2>/dev/null ; /bin/ls /etc/lp/classes \
298		2>/dev/null) >${PRE}
299
300	# if there are no printers configured, enable LP service(s)
301	[[ ! -s "${PRE}" ]] && lp_config_service enable
302
303	# add filters to LP service
304	lp_config_filters
305
306	# add new ppd file to PPD file repositories
307	if [[ -n "${ppd_file}" && -x ${PPDMGR} ]] ; then
308		add_new_ppd_file "${ppd_file}"
309	fi
310
311	# modify LP destination(s)
312	CMD="${PFEXEC} ${LPADMIN}"
313	while [[ -n "$*" ]] ; do	# to deal with multi-word arguments
314		CMD="$CMD \"$1\""
315		# replace the ppd_file originally specified with the -n option
316		# with the one returned from call to ppdmgr
317		if [[ "${1}" = "-n" ]] ; then
318			CMD="$CMD \"${ppd_file}\""
319			shift
320		fi
321		shift
322	done
323	case "$CMD" in
324		*\"-D\")
325			CMD="$CMD \"\""
326		;;
327	esac
328
329	# execute the LP lpadmin command
330	eval $CMD
331	exit_code=$?
332
333	# enumerate LP configured printers after modification
334	POST=/tmp/lpadmin-post.$$
335	(/bin/ls /etc/lp/printers 2>/dev/null ; /bin/ls /etc/lp/classes \
336		2>/dev/null) >${POST}
337
338	# if there are no destinations, disable the service(s)
339	[[ ! -s "${POST}" ]] && lp_config_service disable
340
341	# sync printers.conf with LP configuration
342	lp_config_sync_pconf "${PRE}" "${POST}"
343
344	/bin/rm -f ${PRE} ${POST}
345fi
346
347# Do any printers.conf configuration that is required
348if [[ -n "${delete}" ]] ; then
349	if [[ "${delete}" = "all" ]] ; then
350		[[ $exit_code -eq 0 ]] && delete_all
351   	elif [[ -z "${local}" ]] ; then
352   		${LPSET} -n system -x ${delete}
353   		exit_code=$?
354   	fi
355else
356	if [[ -z "${local}" ]] ; then
357		# if we need a uri, find the "best" one.
358		if [[ -z "${uri}" ]] ; then
359			uri="ipp://${server}/printers/${rem_printer}"
360			${LPSTAT} -p ${uri} >/dev/null 2>&1
361			if [[ $? -ne 0 ]] ; then
362				uri="lpd://${server}/printers/${rem_printer}#Solaris"
363			fi
364		fi
365		# set the bsdaddr
366		bsdaddr="${server},${rem_printer},Solaris"
367
368		if [[ -n "${printer}" ]] ; then
369			${LPSET} -n system \
370				-a "printer-uri-supported=${uri}" \
371				-a "bsdaddr=${bsdaddr}" ${printer}
372			exit_code=$?
373		fi
374
375	fi
376
377	if [[ -n "${printer}" && -n "${description}" ]] ; then
378		${LPSET} -n system \
379			-a "description=${description}" ${printer}
380		exit_code=$?
381	fi
382fi
383
384# if the "default" doesn't resolve a "bsdaddr", the printer is gone, remove it
385${LPGET} -n system -k bsdaddr _default >/dev/null 2>&1 ||
386	${LPSET} -n system -x _default >/dev/null 2>&1
387
388exit $exit_code
389