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