#!/usr/perl5/bin/perl
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#
#
# This program manages the "active" print service selection.
# If called as 'print-service', it takes one of four options.
# Options:
# [-s[et] service [-m]] Select the "active" print service, optionally
# migrating basic print queue configuration.
# [-q[uery]] Display the "active" print service.
# [-e[xport] file] Export basic print queue configuration to
# a file.
# [-i[mport] file] Import basic print queue configuration from
# a file.
#
# If called by any other name, it will look for a corresponding command
# under /usr/lib/{active-service}/bin/{command} and execute that program
# with the original arguments.
#
use Getopt::Long;
use File::Basename;
use File::Copy;
use File::Temp qw/ :POSIX /;
my $cmd = basename($0);
my $LPSTAT = '/usr/bin/lpstat';
my $LPADMIN = '/usr/sbin/lpadmin';
my $ENABLE = '/usr/bin/enable';
my $ACCEPT = '/usr/sbin/accept';
my $SVCADM = '/usr/sbin/svcadm';
my $SVCPROP = '/usr/bin/svcprop';
my $SVCCFG = '/usr/sbin/svccfg';
my $SVC_LP_SCHEDULER = 'print/server';
my $SVC_LP_LPD = 'print/rfc1179';
my $SVC_LP_IPP = 'print/ipp-listener';
my $SVC_LP_PPD = 'print/ppd-cache-update';
my $SVC_CUPS_SCHEDULER = 'cups/scheduler';
my $SVC_CUPS_LPD = 'cups/in-lpd';
sub fatal {
($ENV{"DESKTOP_LAUNCHED"}) &&
exec("/bin/zenity", "--error", "--text=@_");
print STDERR @_;
exit(1);
}
sub usage {
print STDERR <<EOF ;
Usage:
$cmd [-s[et] service [-m]] Select the \"active\" print service,
optionally migrating basic print queue
configuration.
$cmd [-q[uery]] Display the "active" print service.
$cmd [-e[xport] file] Export basic print queue configuration
to a file.
$cmd [-i[mport] file] Import basic print queue configuration
from a file.
EOF
exit(1);
}
sub svcprop {
local ($fmri, $property) = @_;
my $FH;
open($FH, "$SVCPROP -C -p $property $fmri 2>/dev/null |");
$result = <$FH>;
close($FH);
return ($result);
}
sub svccfg {
local ($fmri, $operation) = @_;
my $FH;
open($FH, "$SVCCFG -s $fmri \"$operation\" 2>/dev/null |");
$result = <$FH>;
close($FH);
return ($result);
}
sub svcadm {
local ($operation, @fmris) = @_;
system("$SVCADM $operation -s @fmris");
}
sub print_service {
my $service;
$service = svcprop("$SVC_CUPS_SCHEDULER:default", "general/active");
($service =~ /true/) && ($service = 'cups') || ($service = 'lp');
return ($service);
}
sub print_command {
local($command, @av) = @_;
my $service = print_service();
if (!defined($service)) {
fatal("failed to detect active print service: $!\n");
}
if (! -d "/usr/lib/$service/bin") {
fatal("print service: $service is not installed\n");
}
my $executable = "/usr/lib/$service/bin/$command";
# CUPS has it's own names for enable and disable
($command =~ /(en|dis)able/) && ($service eq 'cups') &&
(! -x $executable) &&
($executable = "/usr/lib/$service/bin/$service$command");
if (! -x $executable) {
fatal("$command is not available from $service print service\n");
}
exec($executable, @ARGV);
}
sub export_print_queues {
local ($path) = @_;
my $service = print_service();
if ($service eq 'lp') {
my $FH, $DFH;
open($FH, ">$path");
open($DFH, "$LPSTAT -v|");
while (<$DFH>) {
if (/device for (.+): (.+)/) {
my $EFH;
print $FH "<Printer $1>\nDeviceURI $2\n";
open($EFH, "$LPSTAT -p $1 -l |");
while (<$EFH>) {
(/Description: (.+)/) &&
print $FH "Info $1\n";
}
close($EFH);
print $FH "</Printer>\n";
}
}
close($DFH);
close($FH);
} else {
copy('/etc/cups/printers.conf', $path);
}
}
sub psystem {
print " @_\n";
system(@_);
}
sub import_print_queues {
local ($path) = @_;
my $service = print_service();
my $FH, %printer, @options;
# store queue info in the 'active' print service
open($FH, "<$path");
while (<$FH>) {
if (/<Printer (.+)>/) {
$printer{'Printer'} = $1;
@options = ();
push(@options, "-p", $1);
} elsif (/([^\s]+)\s(.+)/) {
$printer{$1} = $2;
my $value = $2;
($1 eq 'DeviceURI') &&
push(@options, "-v", $value);
($1 eq 'Info') &&
push(@options, "-D", $value);
} elsif (/<\/Printer>/) {
($service eq 'lp') &&
push(@options, "-m", "uri");
print "importing $printer{'Printer'}...\n";
# create a queue
psystem($LPADMIN, @options);
psystem($ENABLE, $printer{'Printer'});
($printer{'Accepting'} eq 'Yes') &&
psystem($ACCEPT, $printer{'Printer'});
$printer = ();
}
}
close($FH);
}
sub select_service {
my ($service, $migrate) = @_;
my $FH, $queues;
if (! -d "/usr/lib/$service/bin") {
fatal("print service: $service is not installed\n");
}
if ($migrate == 1) {
# export old print queue configuration (if migrating)
$queues = tmpnam();
export_print_queues($queues);
}
# enable/disable the services
if ($service eq 'cups') {
(-f '/etc/printers.conf') && (! -f '/etc/lp/printers.conf') &&
rename('/etc/printers.conf', '/etc/lp/printers.conf');
print("disabling LP services...\n");
svcadm("disable", $SVC_LP_SCHEDULER, $SVC_LP_IPP, $SVC_LP_LPD,
$SVC_LP_PPD);
print("enabling CUPS services...\n");
svcadm("enable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
svccfg("cups/scheduler:default",
"setprop general/active = boolean: true");
system("pkill -USR1 -f '/desktop-print-management-applet'");
} else {
print("disabling CUPS services...\n");
svcadm("disable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
print("enabling LP services...\n");
svcadm("enable", $SVC_LP_SCHEDULER, $SVC_LP_IPP, $SVC_LP_LPD,
$SVC_LP_PPD);
(-f '/etc/lp/printers.conf') &&
rename('/etc/lp/printers.conf', '/etc/printers.conf');
svccfg("cups/scheduler:default", "delprop general/active");
system("pkill -USR1 -f '/desktop-print-management-applet'");
}
# import the new print queue configuration (if migrating)
defined($queues) && import_print_queues($queues);
}
sub query_service {
my $service = print_service();
if (!defined($service)) {
fatal("failed to detect active print service: $!\n");
}
print "active print service: $service\n";
}
if ($cmd eq 'print-service') {
my ($import_path, $export_path, $svc_name, $query, $migrate) = ();
my $res = GetOptions('q|query' => \$query, 's|set=s' => \$service,
'm|migrate' => \$migrate, 'e|export=s' => \$export_path,
'i|import=s' => \$import_path);
($res) || usage();
if (defined($import_path) && !defined($export_path) &&
!defined($query) && !defined($service) && !defined($migrate)) {
import_print_queues($import_path);
} elsif (!defined($import_path) && defined($export_path) &&
!defined($query) && !defined($service) && !defined($migrate)) {
export_print_queues($export_path);
} elsif (!defined($import_path) && !defined($export_path) &&
defined($query) && !defined($service) && !defined($migrate)) {
query_service();
} elsif (!defined($import_path) && !defined($export_path) &&
!defined($query) && defined($service)) {
select_service($service, $migrate);
} else {
usage();
}
} else {
print_command($cmd, @ARGV);
}
exit(0);