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