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