1*6237Sjacobs#!/usr/perl5/bin/perl
2*6237Sjacobs#
3*6237Sjacobs# CDDL HEADER START
4*6237Sjacobs#
5*6237Sjacobs# The contents of this file are subject to the terms of the
6*6237Sjacobs# Common Development and Distribution License (the "License").
7*6237Sjacobs# You may not use this file except in compliance with the License.
8*6237Sjacobs#
9*6237Sjacobs# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*6237Sjacobs# or http://www.opensolaris.org/os/licensing.
11*6237Sjacobs# See the License for the specific language governing permissions
12*6237Sjacobs# and limitations under the License.
13*6237Sjacobs#
14*6237Sjacobs# When distributing Covered Code, include this CDDL HEADER in each
15*6237Sjacobs# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*6237Sjacobs# If applicable, add the following below this CDDL HEADER, with the
17*6237Sjacobs# fields enclosed by brackets "[]" replaced with your own identifying
18*6237Sjacobs# information: Portions Copyright [yyyy] [name of copyright owner]
19*6237Sjacobs#
20*6237Sjacobs# CDDL HEADER END
21*6237Sjacobs#
22*6237Sjacobs# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*6237Sjacobs# Use is subject to license terms.
24*6237Sjacobs#
25*6237Sjacobs# ident	"%Z%%M%	%I%	%E% SMI"
26*6237Sjacobs#
27*6237Sjacobs
28*6237Sjacobs#
29*6237Sjacobs# This program manages the "active" print service selection.
30*6237Sjacobs#   If called as 'print-service', it takes one of four options.
31*6237Sjacobs#   Options:
32*6237Sjacobs#     [-s[et] service [-m]]	Select the "active" print service, optionally
33*6237Sjacobs#				migrating basic print queue configuration.
34*6237Sjacobs#     [-q[uery]]		Display the "active" print service.
35*6237Sjacobs#     [-e[xport] file]		Export basic print queue configuration to
36*6237Sjacobs#				a file.
37*6237Sjacobs#     [-i[mport] file]		Import basic print queue configuration from
38*6237Sjacobs#				a file.
39*6237Sjacobs#
40*6237Sjacobs#   If called by any other name, it will look for a corresponding command
41*6237Sjacobs#   under /usr/lib/{active-service}/bin/{command} and execute that program
42*6237Sjacobs#   with the original arguments.
43*6237Sjacobs#
44*6237Sjacobs
45*6237Sjacobsuse Getopt::Long;
46*6237Sjacobsuse File::Basename;
47*6237Sjacobsuse File::Copy;
48*6237Sjacobsuse File::Temp qw/ :POSIX /;
49*6237Sjacobs
50*6237Sjacobsmy $cmd = basename($0);
51*6237Sjacobs
52*6237Sjacobsmy $LPSTAT = '/usr/bin/lpstat';
53*6237Sjacobsmy $LPADMIN = '/usr/sbin/lpadmin';
54*6237Sjacobsmy $ENABLE = '/usr/bin/enable';
55*6237Sjacobsmy $ACCEPT = '/usr/sbin/accept';
56*6237Sjacobsmy $SVCADM = '/usr/sbin/svcadm';
57*6237Sjacobsmy $SVCPROP = '/usr/bin/svcprop';
58*6237Sjacobsmy $SVCCFG = '/usr/sbin/svccfg';
59*6237Sjacobsmy $SVC_LP_SCHEDULER = 'print/server';
60*6237Sjacobsmy $SVC_LP_LPD = 'print/rfc1179';
61*6237Sjacobsmy $SVC_LP_IPP = 'print/ipp-listener';
62*6237Sjacobsmy $SVC_CUPS_SCHEDULER = 'cups/scheduler';
63*6237Sjacobsmy $SVC_CUPS_LPD = 'cups/in-lpd';
64*6237Sjacobs
65*6237Sjacobssub fatal {
66*6237Sjacobs	print STDERR @_;
67*6237Sjacobs	exit(1);
68*6237Sjacobs}
69*6237Sjacobs
70*6237Sjacobssub usage {
71*6237Sjacobs	print STDERR <<EOF ;
72*6237SjacobsUsage:
73*6237Sjacobs  $cmd [-s[et] service [-m]]	Select the \"active\" print service,
74*6237Sjacobs					optionally migrating basic print queue
75*6237Sjacobs					configuration.
76*6237Sjacobs  $cmd [-q[uery]]		Display the "active" print service.
77*6237Sjacobs  $cmd [-e[xport] file]	Export basic print queue configuration
78*6237Sjacobs					to a file.
79*6237Sjacobs  $cmd [-i[mport] file]	Import basic print queue configuration
80*6237Sjacobs					from a file.
81*6237SjacobsEOF
82*6237Sjacobs	exit(1);
83*6237Sjacobs}
84*6237Sjacobs
85*6237Sjacobssub svcprop {
86*6237Sjacobs	local ($fmri, $property) = @_;
87*6237Sjacobs	my $FH;
88*6237Sjacobs
89*6237Sjacobs	open($FH, "$SVCPROP -C -p $property $fmri 2>/dev/null |");
90*6237Sjacobs	$result = <$FH>;
91*6237Sjacobs	close($FH);
92*6237Sjacobs
93*6237Sjacobs	return ($result);
94*6237Sjacobs}
95*6237Sjacobs
96*6237Sjacobssub svccfg {
97*6237Sjacobs	local ($fmri, $operation) = @_;
98*6237Sjacobs	my $FH;
99*6237Sjacobs
100*6237Sjacobs	open($FH, "$SVCCFG -s $fmri \"$operation\" 2>/dev/null |");
101*6237Sjacobs	$result = <$FH>;
102*6237Sjacobs	close($FH);
103*6237Sjacobs
104*6237Sjacobs	return ($result);
105*6237Sjacobs}
106*6237Sjacobs
107*6237Sjacobssub svcadm {
108*6237Sjacobs	local ($operation, @fmris) = @_;
109*6237Sjacobs
110*6237Sjacobs	system("$SVCADM $operation -s @fmris");
111*6237Sjacobs}
112*6237Sjacobs
113*6237Sjacobs
114*6237Sjacobssub print_service {
115*6237Sjacobs	my $service;
116*6237Sjacobs
117*6237Sjacobs	$service = svcprop("$SVC_CUPS_SCHEDULER:default", "general/active");
118*6237Sjacobs	($service =~ /true/) && ($service = 'cups') || ($service = 'lp');
119*6237Sjacobs
120*6237Sjacobs	return ($service);
121*6237Sjacobs}
122*6237Sjacobs
123*6237Sjacobssub print_command {
124*6237Sjacobs	local($command, @av) = @_;
125*6237Sjacobs	my $service = print_service();
126*6237Sjacobs
127*6237Sjacobs	if (!defined($service)) {
128*6237Sjacobs		fatal("failed to detect active print service: $!\n");
129*6237Sjacobs	}
130*6237Sjacobs
131*6237Sjacobs	if (! -d "/usr/lib/$service/bin") {
132*6237Sjacobs		fatal("print service: $service is not installed\n");
133*6237Sjacobs	}
134*6237Sjacobs
135*6237Sjacobs	my $executable = "/usr/lib/$service/bin/$command";
136*6237Sjacobs	# CUPS has it's own names for enable and disable
137*6237Sjacobs	($command =~ /(en|dis)able/) && ($service eq 'cups') &&
138*6237Sjacobs		(! -x $executable) &&
139*6237Sjacobs		($executable = "/usr/lib/$service/bin/$service$command");
140*6237Sjacobs
141*6237Sjacobs	if (! -x $executable) {
142*6237Sjacobs		fatal("$command is not available from $service print service\n");
143*6237Sjacobs	}
144*6237Sjacobs
145*6237Sjacobs	exec($executable, @ARGV);
146*6237Sjacobs}
147*6237Sjacobs
148*6237Sjacobssub export_print_queues {
149*6237Sjacobs	local ($path) = @_;
150*6237Sjacobs	my $service = print_service();
151*6237Sjacobs
152*6237Sjacobs	if ($service eq 'lp') {
153*6237Sjacobs		my $FH, $DFH;
154*6237Sjacobs
155*6237Sjacobs		open($FH, ">$path");
156*6237Sjacobs		open($DFH, "$LPSTAT -v|");
157*6237Sjacobs		while (<$DFH>) {
158*6237Sjacobs			if (/device for (.+): (.+)/) {
159*6237Sjacobs				my $EFH;
160*6237Sjacobs
161*6237Sjacobs				print $FH "<Printer $1>\nDeviceURI $2\n";
162*6237Sjacobs				open($EFH, "$LPSTAT -p $1 -l |");
163*6237Sjacobs				while (<$EFH>) {
164*6237Sjacobs					(/Description: (.+)/) &&
165*6237Sjacobs						print $FH "Info $1\n";
166*6237Sjacobs				}
167*6237Sjacobs				close($EFH);
168*6237Sjacobs				print $FH "</Printer>\n";
169*6237Sjacobs			}
170*6237Sjacobs		}
171*6237Sjacobs		close($DFH);
172*6237Sjacobs		close($FH);
173*6237Sjacobs	} else {
174*6237Sjacobs		copy('/etc/cups/printers.conf', $path);
175*6237Sjacobs	}
176*6237Sjacobs}
177*6237Sjacobs
178*6237Sjacobssub psystem {
179*6237Sjacobs	print "  @_\n";
180*6237Sjacobs	system(@_);
181*6237Sjacobs}
182*6237Sjacobs
183*6237Sjacobssub import_print_queues {
184*6237Sjacobs	local ($path) = @_;
185*6237Sjacobs	my $service = print_service();
186*6237Sjacobs	my $FH, %printer, @options;
187*6237Sjacobs
188*6237Sjacobs	# store queue info in the 'active' print service
189*6237Sjacobs	open($FH, "<$path");
190*6237Sjacobs	while (<$FH>) {
191*6237Sjacobs		if (/<Printer (.+)>/) {
192*6237Sjacobs			$printer{'Printer'} = $1;
193*6237Sjacobs			@options = ();
194*6237Sjacobs			push(@options, "-p", $1);
195*6237Sjacobs		} elsif (/([^\s]+)\s(.+)/) {
196*6237Sjacobs			$printer{$1} = $2;
197*6237Sjacobs			my $value = $2;
198*6237Sjacobs			($1 eq 'DeviceURI') &&
199*6237Sjacobs				push(@options, "-v", $value);
200*6237Sjacobs			($1 eq 'Info') &&
201*6237Sjacobs				push(@options, "-D", $value);
202*6237Sjacobs		} elsif (/<\/Printer>/) {
203*6237Sjacobs			($service eq 'lp') &&
204*6237Sjacobs				push(@options, "-m", "uri");
205*6237Sjacobs			print "importing $printer{'Printer'}...\n";
206*6237Sjacobs			# create a queue
207*6237Sjacobs			psystem($LPADMIN, @options);
208*6237Sjacobs			psystem($ENABLE, $printer{'Printer'});
209*6237Sjacobs			($printer{'Accepting'} eq 'Yes') &&
210*6237Sjacobs				psystem($ACCEPT, $printer{'Printer'});
211*6237Sjacobs			$printer = ();
212*6237Sjacobs		}
213*6237Sjacobs	}
214*6237Sjacobs	close($FH);
215*6237Sjacobs}
216*6237Sjacobs
217*6237Sjacobssub select_service {
218*6237Sjacobs	my ($service, $migrate) = @_;
219*6237Sjacobs	my $FH, $queues;
220*6237Sjacobs
221*6237Sjacobs	if (! -d "/usr/lib/$service/bin") {
222*6237Sjacobs		fatal("print service: $service is not installed\n");
223*6237Sjacobs	}
224*6237Sjacobs
225*6237Sjacobs	if ($migrate == 1) {
226*6237Sjacobs		# export old print queue configuration (if migrating)
227*6237Sjacobs		$queues = tmpnam();
228*6237Sjacobs		export_print_queues($queues);
229*6237Sjacobs	}
230*6237Sjacobs
231*6237Sjacobs	# enable/disable the services
232*6237Sjacobs	if ($service eq 'cups') {
233*6237Sjacobs		print("disabling LP services...\n");
234*6237Sjacobs		svcadm("disable", $SVC_LP_SCHEDULER, $SVC_LP_IPP, $SVC_LP_LPD);
235*6237Sjacobs		print("enabling CUPS services...\n");
236*6237Sjacobs		svcadm("enable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
237*6237Sjacobs		svccfg("cups/scheduler:default",
238*6237Sjacobs			"setprop general/active = boolean: true");
239*6237Sjacobs	} else {
240*6237Sjacobs		print("disabling CUPS services...\n");
241*6237Sjacobs		svcadm("disable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
242*6237Sjacobs		print("enabling LP services...\n");
243*6237Sjacobs		svcadm("enable", $SVC_LP_SCHEDULER, $SVC_LP_IPP, $SVC_LP_LPD);
244*6237Sjacobs		svccfg("cups/scheduler:default", "delprop general/active");
245*6237Sjacobs	}
246*6237Sjacobs
247*6237Sjacobs	# import the new print queue configuration (if migrating)
248*6237Sjacobs	defined($queues) && import_print_queues($queues);
249*6237Sjacobs}
250*6237Sjacobs
251*6237Sjacobssub query_service {
252*6237Sjacobs	my $service = print_service();
253*6237Sjacobs
254*6237Sjacobs	if (!defined($service)) {
255*6237Sjacobs		fatal("failed to detect active print service: $!\n");
256*6237Sjacobs	}
257*6237Sjacobs	print "active print service: $service\n";
258*6237Sjacobs}
259*6237Sjacobs
260*6237Sjacobsif ($cmd eq 'print-service') {
261*6237Sjacobs	my ($import_path, $export_path, $svc_name, $query, $migrate) = ();
262*6237Sjacobs
263*6237Sjacobs	my $res = GetOptions('q|query' => \$query, 's|set=s' => \$service,
264*6237Sjacobs		'm|migrate' => \$migrate, 'e|export=s' => \$export_path,
265*6237Sjacobs		'i|import=s' => \$import_path);
266*6237Sjacobs
267*6237Sjacobs	($res) || usage();
268*6237Sjacobs
269*6237Sjacobs	if (defined($import_path) && !defined($export_path) &&
270*6237Sjacobs	    !defined($query) && !defined($service) && !defined($migrate)) {
271*6237Sjacobs		import_print_queues($import_path);
272*6237Sjacobs	} elsif (!defined($import_path) && defined($export_path) &&
273*6237Sjacobs		 !defined($query) && !defined($service) && !defined($migrate)) {
274*6237Sjacobs		export_print_queues($export_path);
275*6237Sjacobs	} elsif (!defined($import_path) && !defined($export_path) &&
276*6237Sjacobs		 defined($query) && !defined($service) && !defined($migrate)) {
277*6237Sjacobs		query_service();
278*6237Sjacobs	} elsif (!defined($import_path) && !defined($export_path) &&
279*6237Sjacobs		 !defined($query) && defined($service)) {
280*6237Sjacobs		select_service($service, $migrate);
281*6237Sjacobs	} else {
282*6237Sjacobs		usage();
283*6237Sjacobs	}
284*6237Sjacobs} else {
285*6237Sjacobs	print_command($cmd, @ARGV);
286*6237Sjacobs}
287*6237Sjacobs
288*6237Sjacobsexit(0);
289