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