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_CUPS_SCHEDULER = 'cups/scheduler';
63my $SVC_CUPS_LPD = 'cups/in-lpd';
64
65sub fatal {
66	print STDERR @_;
67	exit(1);
68}
69
70sub usage {
71	print STDERR <<EOF ;
72Usage:
73  $cmd [-s[et] service [-m]]	Select the \"active\" print service,
74					optionally migrating basic print queue
75					configuration.
76  $cmd [-q[uery]]		Display the "active" print service.
77  $cmd [-e[xport] file]	Export basic print queue configuration
78					to a file.
79  $cmd [-i[mport] file]	Import basic print queue configuration
80					from a file.
81EOF
82	exit(1);
83}
84
85sub svcprop {
86	local ($fmri, $property) = @_;
87	my $FH;
88
89	open($FH, "$SVCPROP -C -p $property $fmri 2>/dev/null |");
90	$result = <$FH>;
91	close($FH);
92
93	return ($result);
94}
95
96sub svccfg {
97	local ($fmri, $operation) = @_;
98	my $FH;
99
100	open($FH, "$SVCCFG -s $fmri \"$operation\" 2>/dev/null |");
101	$result = <$FH>;
102	close($FH);
103
104	return ($result);
105}
106
107sub svcadm {
108	local ($operation, @fmris) = @_;
109
110	system("$SVCADM $operation -s @fmris");
111}
112
113
114sub print_service {
115	my $service;
116
117	$service = svcprop("$SVC_CUPS_SCHEDULER:default", "general/active");
118	($service =~ /true/) && ($service = 'cups') || ($service = 'lp');
119
120	return ($service);
121}
122
123sub print_command {
124	local($command, @av) = @_;
125	my $service = print_service();
126
127	if (!defined($service)) {
128		fatal("failed to detect active print service: $!\n");
129	}
130
131	if (! -d "/usr/lib/$service/bin") {
132		fatal("print service: $service is not installed\n");
133	}
134
135	my $executable = "/usr/lib/$service/bin/$command";
136	# CUPS has it's own names for enable and disable
137	($command =~ /(en|dis)able/) && ($service eq 'cups') &&
138		(! -x $executable) &&
139		($executable = "/usr/lib/$service/bin/$service$command");
140
141	if (! -x $executable) {
142		fatal("$command is not available from $service print service\n");
143	}
144
145	exec($executable, @ARGV);
146}
147
148sub export_print_queues {
149	local ($path) = @_;
150	my $service = print_service();
151
152	if ($service eq 'lp') {
153		my $FH, $DFH;
154
155		open($FH, ">$path");
156		open($DFH, "$LPSTAT -v|");
157		while (<$DFH>) {
158			if (/device for (.+): (.+)/) {
159				my $EFH;
160
161				print $FH "<Printer $1>\nDeviceURI $2\n";
162				open($EFH, "$LPSTAT -p $1 -l |");
163				while (<$EFH>) {
164					(/Description: (.+)/) &&
165						print $FH "Info $1\n";
166				}
167				close($EFH);
168				print $FH "</Printer>\n";
169			}
170		}
171		close($DFH);
172		close($FH);
173	} else {
174		copy('/etc/cups/printers.conf', $path);
175	}
176}
177
178sub psystem {
179	print "  @_\n";
180	system(@_);
181}
182
183sub import_print_queues {
184	local ($path) = @_;
185	my $service = print_service();
186	my $FH, %printer, @options;
187
188	# store queue info in the 'active' print service
189	open($FH, "<$path");
190	while (<$FH>) {
191		if (/<Printer (.+)>/) {
192			$printer{'Printer'} = $1;
193			@options = ();
194			push(@options, "-p", $1);
195		} elsif (/([^\s]+)\s(.+)/) {
196			$printer{$1} = $2;
197			my $value = $2;
198			($1 eq 'DeviceURI') &&
199				push(@options, "-v", $value);
200			($1 eq 'Info') &&
201				push(@options, "-D", $value);
202		} elsif (/<\/Printer>/) {
203			($service eq 'lp') &&
204				push(@options, "-m", "uri");
205			print "importing $printer{'Printer'}...\n";
206			# create a queue
207			psystem($LPADMIN, @options);
208			psystem($ENABLE, $printer{'Printer'});
209			($printer{'Accepting'} eq 'Yes') &&
210				psystem($ACCEPT, $printer{'Printer'});
211			$printer = ();
212		}
213	}
214	close($FH);
215}
216
217sub select_service {
218	my ($service, $migrate) = @_;
219	my $FH, $queues;
220
221	if (! -d "/usr/lib/$service/bin") {
222		fatal("print service: $service is not installed\n");
223	}
224
225	if ($migrate == 1) {
226		# export old print queue configuration (if migrating)
227		$queues = tmpnam();
228		export_print_queues($queues);
229	}
230
231	# enable/disable the services
232	if ($service eq 'cups') {
233		print("disabling LP services...\n");
234		svcadm("disable", $SVC_LP_SCHEDULER, $SVC_LP_IPP, $SVC_LP_LPD);
235		print("enabling CUPS services...\n");
236		svcadm("enable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
237		svccfg("cups/scheduler:default",
238			"setprop general/active = boolean: true");
239	} else {
240		print("disabling CUPS services...\n");
241		svcadm("disable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
242		print("enabling LP services...\n");
243		svcadm("enable", $SVC_LP_SCHEDULER, $SVC_LP_IPP, $SVC_LP_LPD);
244		svccfg("cups/scheduler:default", "delprop general/active");
245	}
246
247	# import the new print queue configuration (if migrating)
248	defined($queues) && import_print_queues($queues);
249}
250
251sub query_service {
252	my $service = print_service();
253
254	if (!defined($service)) {
255		fatal("failed to detect active print service: $!\n");
256	}
257	print "active print service: $service\n";
258}
259
260if ($cmd eq 'print-service') {
261	my ($import_path, $export_path, $svc_name, $query, $migrate) = ();
262
263	my $res = GetOptions('q|query' => \$query, 's|set=s' => \$service,
264		'm|migrate' => \$migrate, 'e|export=s' => \$export_path,
265		'i|import=s' => \$import_path);
266
267	($res) || usage();
268
269	if (defined($import_path) && !defined($export_path) &&
270	    !defined($query) && !defined($service) && !defined($migrate)) {
271		import_print_queues($import_path);
272	} elsif (!defined($import_path) && defined($export_path) &&
273		 !defined($query) && !defined($service) && !defined($migrate)) {
274		export_print_queues($export_path);
275	} elsif (!defined($import_path) && !defined($export_path) &&
276		 defined($query) && !defined($service) && !defined($migrate)) {
277		query_service();
278	} elsif (!defined($import_path) && !defined($export_path) &&
279		 !defined($query) && defined($service)) {
280		select_service($service, $migrate);
281	} else {
282		usage();
283	}
284} else {
285	print_command($cmd, @ARGV);
286}
287
288exit(0);
289