Files
scst/scstadmin/scstadmin.sysfs
T
Mark Buechler 627b323dbe - Missed a spot where scst base attributes are getting written
even if they aren't key attributes.



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1854 d57e44dd-8a1f-0410-8b47-8ef2f437770f
2010-07-21 20:26:47 +00:00

3173 lines
84 KiB
Perl
Executable File

#!/usr/bin/perl
$Version = 'SCST Configurator v2.0.0';
# Configures SCST
#
# Author: Mark R. Buechler
# License: GPLv2
# Copyright (c) 2005-2010 Mark R. Buechler
sub usage
{
die <<"EndUsage";
$Version
Usage:
General Operations
-config <config> : Configure SCST given the specified <file>.
-clear_config : Clear all SCST configuration.
-write_config <file> : Writes the current configuration out <file>.
-check_config <file> : Checks the saved configuration in <file>.
Query Operations
-list_handler [<hndlr>] : List all available handlers or specific <hndlr>.
-list_device [<device>] : List all open devices or specific <device>.
-list_driver [<driver>] : List all available drivers or specific <driver>.
-list_target [<target>] : List all available targets or specific <target>.
[-driver <driver>]
-list_group [<group>] : List all configured groups, or specific <group>.
[-driver <driver>]
[-target <target>]
-list_scst_attr : List add attributes for SCST.
-list_hnd_attr <hndlr> : List all attributes for a given handler.
-list_dev_attr <device> : List all attributes for a given device.
-list_drv_attr <driver> : List all attributes for a given driver.
-list_tgt_attr <target> : List all attributes for a given driver/target.
-driver <driver>
-list_lun_attr <lun> : List all attributes for a driver/target/lun.
-driver <driver>
-target <target>
-group <group>
-list_ini_attr <ini> : List all attributes for a driver/target/initiator
-driver <driver>
-target <target>
-group <group>
-list_sessions : List all current initiator sessions.
Set Attribute Operations
-set_scst_attr : Sets SCST attribute(s) <p> to value <v>.
-attributes <p=v,...>
-set_hnd_attr <hndlr> : Sets handler attribute(s) <p> to value <v>.
-attributes <p=v,...>
-set_dev_attr <device> : Sets device attributes(s) <p> to value <v>.
-attributes <p=v,...>
-set_drv_attr <driver> : Sets driver attribute(s) <p> to value <v>.
-attributes <p=v,...>
-set_tgt_attr <target> : Sets target attribute(s) <p> to value <v>.
-driver <driver>
-attributes <p=v,...>
-set_lun_attr <lun> : Sets LUN attribute(s) <p> to value <v>.
-driver <driver>
-target <target>
-group <group>
-attributes <p=v,...>
-set_ini_attr <ini> : Sets initiator attribute(s) <p> to value <v>.
-driver <driver>
-target <target>
-group <group>
-attributes <p=v,...>
Add Dynamic Attribute Operations
-add_drv_attr <driver> : Adds driver attribute(s) <p> to value <v>.
-attributes <p=v,...>
-add_tgt_attr <target> : Adds target attribute(s) <p> to value <v>.
-driver <driver>
-attributes <p=v,...>
Remove Dynamic Attribute Operations
-rem_drv_attr <driver> : Remove driver attribute(s) <p> to value <v>.
-attributes <p=v,...>
-rem_tgt_attr <target> : Remove target attribute(s) <p> to value <v>.
-driver <driver>
-attributes <p=v,...>
Device Operations
-open_dev <device> : Adds a new device using handler <handler>.
-handler <handler>
-attributes <p=v,...>
-resync_dev <device> : Resync the device size with the initiator(s).
-close_dev <device> : Closes a device belonging to handler <handler>.
-handler <handler>
Group Operations
-add_group <group> : Add a group to a given driver & target.
-driver <driver>
-target <target>
-remove_group <group> : Remove a group from a given driver & target.
-driver <driver>
-target <target>
Initiator Operations
-add_init <init> : Adds an initiator to a group.
-driver <driver>
-target <target>
-group <group>
-remove_init <user> : Removes an initiator from a group.
-driver <driver>
-target <target>
-group <group>
-move_init <init> : Moves an initiator from one group to another.
-driver <driver>
-target <target>
-group <group 1>
-to <group 2>
-clear_inits : Clear all initiators from a given group.
-driver <driver>
-target <target>
-group <group>
Target LUN Operations
-add_lun <lun> : Adds a given device to a group.
-driver <driver>
-target <target>
-group <group>
-device <device>
-attributes <p=v,...>
-remove_lun <lun> : Remove a LUN from a group.
-driver <driver>
-target <target>
-group <group>
-replace_lun <lun> : Replaces a LUN's device with a different one.
-driver <driver>
-target <target>
-group <group>
-device <device>
-attributes <p=v,...>
-clear_luns : Clear all LUNs within a group.
-driver <driver>
-target <target>
-group <group>
Target Driver Operations
-enable_target <t> : Enable target mode for a given driver & target.
-driver <driver>
-disable_target <t> : Disable target mode for a given driver & target.
-driver <driver>
-issue_lip : Issue LIP on all target-enabled FC fabrics.
Options
-nonkey : When writing a configuration file, store non-key
attributes as well.
-force : Force all configuration changes,
even deletions (DANGER!).
-noprompt : Do not prompt or pause. Use with caution!
Debugging (limited support)
-debug : Debug mode - don\'t do anything destructive.
Examples:
Open a new device:
scstadmin -open_dev DISK01 -handler vdisk_fileio \
-attributes filename=/vdisks/disk01.dsk,read_only
Setting the T10 Device ID of a device
scstadmin -set_dev_attr DISK01 -options t10_dev_id=0x2345
Create a new security group:
scstadmin -add_group HOST01 -driver qla2x00t \
-target 50:06:0B:00:00:39:71:78
Rename a security group:
scstadmin -rename_group HOST01 -to SERVER01 -driver qla2x00t \
-target 50:06:0B:00:00:39:71:78
Add a LUN to a group:
scstadmin -add_lun 1 -driver qla2x00t -target 50:06:0B:00:00:39:71:78 \
-group HOST01 -device DISK01 -attributes read_only=1
Enable target mode for fibre card specifying its WWN
scstadmin -enable_target 50:06:0B:00:00:39:71:78 -driver qla2x00t
Tell all initiators to rescan LUNs:
scstadmin -issue_lip
EndUsage
}
use SCST::SCST 0.9.0;
use Getopt::Long;
use IO::File;
use IO::Dir;
use POSIX;
use strict;
my $_DEF_CONFIG_ = '/etc/scst.conf';
use constant {
TRUE => 1,
FALSE => 0,
DEF_CONFIG => '/etc/scst.conf',
MAX_LUNS => 255,
};
my $SCST;
my $CONFIG;
my $_DEBUG_;
my %CURRENT;
$SIG{INT} = \&commitSuicide;
use vars qw($Version);
&main();
sub getArgs {
my $applyConfig;
my $clearConfig;
my $writeConfig;
my $checkConfig;
my $listHandler;
my $listDevice;
my $listDriver;
my $listTarget;
my $listGroup;
my $listSessions;
my $listScstAttr;
my $listHandlerAttr;
my $listDeviceAttr;
my $listDriverAttr;
my $listTargetAttr;
my $listLunAttr;
my $listInitiatorAttr;
my $setScstAttr;
my $setHandlerAttr;
my $setDeviceAttr;
my $setDriverAttr;
my $setTargetAttr;
my $setLunAttr;
my $setInitiatorAttr;
my $openDev;
my $closeDev;
my $resyncDev;
my $addGroup;
my $removeGroup;
my $addInitiator;
my $removeInitiator;
my $moveInitiator;
my $clearInitiators;
my $addLun;
my $removeLun;
my $replaceLun;
my $clearLuns;
my $enableTarget;
my $disableTarget;
my $issueLip;
my $handler;
my $attributes;
my $driver;
my $target;
my $group;
my $to;
my $device;
my $nonkey;
my $noprompt;
my $force;
my $p = new Getopt::Long::Parser;
if (!$p->getoptions('config:s' => \$applyConfig,
'clear_config' => \$clearConfig,
'write_config=s' => \$writeConfig,
'check_config:s' => \$checkConfig,
'list_handler:s' => \$listHandler,
'list_device:s' => \$listDevice,
'list_driver:s' => \$listDriver,
'list_target:s' => \$listTarget,
'list_group:s' => \$listGroup,
'list_sessions' => \$listSessions,
'list_scst_attr' => \$listScstAttr,
'list_hnd_attr=s' => \$listHandlerAttr,
'list_dev_attr=s' => \$listDeviceAttr,
'list_drv_attr=s' => \$listDriverAttr,
'list_tgt_attr=s' => \$listTargetAttr,
'list_lun_attr=s' => \$listLunAttr,
'list_ini_attr=s' => \$listInitiatorAttr,
'set_scst_attr' => \$setScstAttr,
'set_hnd_attr=s' => \$setHandlerAttr,
'set_dev_attr=s' => \$setDeviceAttr,
'set_drv_attr=s' => \$setDriverAttr,
'set_tgt_attr=s' => \$setTargetAttr,
'set_lun_attr=s' => \$setLunAttr,
'set_ini_attr=s' => \$setInitiatorAttr,
'open_dev=s' => \$openDev,
'close_dev=s' => \$closeDev,
'resync_dev=s' => \$resyncDev,
'add_group=s' => \$addGroup,
'remove_group=s' => \$removeGroup,
'add_init=s' => \$addInitiator,
'remove_init=s' => \$removeInitiator,
'move_init=s' => \$moveInitiator,
'clear_inits' => \$clearInitiators,
'add_lun=s' => \$addLun,
'remove_lun=s' => \$removeLun,
'replace_lun=s' => \$replaceLun,
'clear_luns=s' => \$clearLuns,
'enable_target=s' => \$enableTarget,
'disable_target=s' => \$disableTarget,
'issue_lip' => \$issueLip,
'handler=s' => \$handler,
'attributes=s' => \$attributes,
'driver=s' => \$driver,
'target=s' => \$target,
'group=s' => \$group,
'to=s' => \$to,
'device=s' => \$device,
'nonkey' => \$nonkey,
'noprompt' => \$noprompt,
'force' => \$force,
'debug' => \$_DEBUG_)) {
usage();
}
$_DEBUG_ = TRUE if (defined($_DEBUG_));
$force = TRUE if (defined($force));
$noprompt = TRUE if (defined($noprompt));
$clearInitiators = TRUE if (defined($clearInitiators));
$clearLuns = TRUE if (defined($clearLuns));
$issueLip = TRUE if (defined($issueLip));
$listSessions = TRUE if (defined($listSessions));
$listScstAttr = TRUE if (defined($listScstAttr));
$setScstAttr = TRUE if (defined($setScstAttr));
$nonkey = TRUE if (defined($nonkey));
my $query_mode = defined($listHandler) || defined($listDevice) || defined($listDriver) ||
defined($listTarget) || defined($listGroup) || defined($listSessions) || defined($listScstAttr) ||
defined($listHandlerAttr) || defined($listDeviceAttr) || defined($listDriverAttr) ||
defined($listTargetAttr) || defined($listLunAttr) || defined($listInitiatorAttr);
my $set_mode = defined($setScstAttr) + defined($setHandlerAttr) + defined($setDeviceAttr) +
defined($setDriverAttr) + defined($setTargetAttr) + defined($setLunAttr) + defined($setInitiatorAttr);
my $op_mode = defined($clearConfig) + defined($writeConfig) + defined($checkConfig) +
defined($openDev) + defined($closeDev) + defined($addGroup) + defined($removeGroup) +
defined($addInitiator) + defined($removeInitiator) + defined($clearInitiators) +
defined($addLun) + defined($removeLun) + defined($replaceLun) + defined($clearLuns) +
defined($enableTarget) + defined($disableTarget) + defined($issueLip);
if (($query_mode + $set_mode + $op_mode) > 1) {
print "Please specify only one non-query operation at a time.\n";
usage();
}
if ($clearConfig && !$force) {
print "Please specify -force with -clear_config.\n";
usage();
}
if ($listTargetAttr && !$driver) {
print "Please specify -driver with -list_tgt_attr.\n";
usage();
}
if ($listLunAttr && (!$driver || !$target || !$group)) {
print "Please specify -driver -target and -group with -list_lun_attr.\n";
usage();
}
if ($listInitiatorAttr && (!$driver || !$target || !$group)) {
print "Please specify -driver -target and -group with -list_ini_attr.\n";
usage();
}
if ($setScstAttr && !$attributes) {
print "Please specify -attributes with -set_scst_attr.\n";
usage();
}
if ($setHandlerAttr && !$attributes) {
print "Please specify -attributes with -set_hnd_attr.\n";
usage();
}
if ($setDeviceAttr && !$attributes) {
print "Please specify -attributes with -set_dev_attr.\n";
usage();
}
if ($setDriverAttr && !$attributes) {
print "Please specify -attributes with -set_drv_attr.\n";
usage();
}
if ($setTargetAttr && (!$driver || !$attributes)) {
print "Please specify -driver and -attributes with -set_tgt_attr.\n";
usage();
}
if ($setLunAttr && (!$driver || !$target || !$group || !$attributes)) {
print "Please specify -driver -target -group and -attributes with -set_lun_attr.\n";
usage();
}
if ($setDeviceAttr && (!$driver || !$target || !$group || !$attributes)) {
print "Please specify -driver -target -group and -attributes with -set_ini_attr.\n";
usage();
}
if (($openDev || $closeDev) && !$handler) {
print "Please specify -handler with -open_dev/-close_dev.\n";
usage();
}
if (($addGroup || $removeGroup) && (!$driver || !$target)) {
print "Please specify -driver and -target with -add_group/-remove_group.\n";
usage();
}
if (($addInitiator || $removeInitiator || $clearInitiators) &&
(!$target || !$driver || !$group)) {
print "Please specify -driver -target and -group with ".
"-add_init/-remove_init/-clear_inits.\n";
usage();
}
if ($moveInitiator && (!$driver || !$target || !$group || !$to)) {
print "Please specify -driver -target -group and -to with -move_init.\n";
usage();
}
if (($addLun || $replaceLun || $removeLun) && (!$driver || !$target || !$group || !$device)) {
print "Please specify -driver -target -group and -device with -add_lun/-replace_lun.\n";
usage();
}
if ($clearLuns && (!$driver || !$target || !$group)) {
print "Please specify -driver -target and -group with -remove_lun/-clear_luns.\n";
usage();
}
if ($nonkey && !defined($writeConfig)) {
print "Option -nonkey ignored since -writeConfig was not specified.\n";
}
$applyConfig = $_DEF_CONFIG_ if (defined($applyConfig) && !$applyConfig);
$checkConfig = $_DEF_CONFIG_ if (defined($checkConfig) && !$checkConfig);
my %_attributes;
if ($attributes) {
foreach my $attribute (split(/\,/, $attributes)) {
my $value;
if ($attribute =~ /\=/) {
$value = TRUE;
} else {
($attribute, $value) = split(/\=/, $attribute, 2);
}
$_attributes{$attribute} = $value;
}
}
return ($applyConfig, $clearConfig, $writeConfig, $checkConfig,
$listScstAttr, $listHandler, $listDevice, $listDriver, $listTarget, $listGroup,
$listSessions, $listHandlerAttr, $listDeviceAttr, $listDriverAttr, $listTargetAttr,
$listLunAttr, $listInitiatorAttr, $setScstAttr, $setHandlerAttr, $setDeviceAttr,
$setDriverAttr, $setTargetAttr, $setLunAttr, $setInitiatorAttr,
$openDev, $closeDev, $resyncDev,
$addGroup, $removeGroup,
$addInitiator, $removeInitiator, $moveInitiator, $clearInitiators,
$addLun, $removeLun, $replaceLun, $clearLuns,
$enableTarget, $disableTarget, $issueLip,
$handler, \%_attributes,
$driver, $target, $group, $to, $device,
$nonkey, $noprompt, $force);
}
sub main {
my $rc;
STDOUT->autoflush(1);
# We need to run as root
if ( $> ) {die("This program must run as root.\n");}
my ($applyConfig, $clearConfig, $writeConfig, $checkConfig,
$listScstAttr, $listHandler, $listDevice, $listDriver, $listTarget, $listGroup,
$listSessions, $listHandlerAttr, $listDeviceAttr, $listDriverAttr, $listTargetAttr,
$listLunAttr, $listInitiatorAttr, $setScstAttr, $setHandlerAttr, $setDeviceAttr,
$setDriverAttr, $setTargetAttr, $setLunAttr, $setInitiatorAttr,
$openDev, $closeDev, $resyncDev,
$addGroup, $removeGroup,
$addInitiator, $removeInitiator, $moveInitiator, $clearInitiators,
$addLun, $removeLun, $replaceLun, $clearLuns,
$enableTarget, $disableTarget, $issueLip,
$handler, $attributes,
$driver, $target, $group, $to, $device,
$nonkey, $noprompt, $force) = getArgs();
$SCST = new SCST::SCST($_DEBUG_);
readWorkingConfig();
my $all_good;
SWITCH: {
$applyConfig && do {
$rc = checkConfiguration($applyConfig);
immediateExit("Configuration has errors, aborting.") if ($rc);
$rc = applyConfiguration($applyConfig, $force);
last SWITCH;
};
$checkConfig && do {
$rc = checkConfiguration($checkConfig);
last SWITCH;
};
$writeConfig && do {
$rc = writeConfiguration($writeConfig, $nonkey);
last SWITCH;
};
$clearConfig && do {
$rc = clearConfiguration($noprompt, $force);
last SWITCH;
};
defined($listHandler) && do {
$rc = listHandlers($listHandler);
$all_good = TRUE;
};
defined($listDevice) && do {
$rc = listDevices($listDevice);
$all_good = TRUE;
};
defined($listDriver) && do {
$rc = listDrivers($listDriver);
$all_good = TRUE;
};
defined($listTarget) && do {
$rc = listTargets($listTarget, $driver);
$all_good = TRUE;
};
defined($listGroup) && do {
$rc = listGroups($listGroup, $driver, $target);
$all_good = TRUE;
};
$listSessions && do {
$rc = listSessions();
$all_good = TRUE;
};
$listScstAttr && do {
$rc = listScstAttr();
$all_good = TRUE;
};
$listHandlerAttr && do {
$rc = listHandlerAttributes($listHandlerAttr);
$all_good = TRUE;
};
$listDeviceAttr && do {
$rc = listDeviceAttributes($listDeviceAttr);
$all_good = TRUE;
};
$listDriverAttr && do {
$rc = listDriverAttributes($listHandlerAttr);
$all_good = TRUE;
};
$listTargetAttr && do {
$rc = listTargetAttributes($listTargetAttr, $driver);
$all_good = TRUE;
};
$listLunAttr && do {
$rc = listLunAttributes($listLunAttr, $driver, $target, $group);
$all_good = TRUE;
};
$listInitiatorAttr && do {
$rc = listInitiatorAttributes($listInitiatorAttr, $driver, $target, $group);
$all_good = TRUE;
};
$setScstAttr && do {
$rc = setScstAttributes($attributes);
last SWITCH;
};
$setHandlerAttr && do {
$rc = setHandlerAttributes($setHandlerAttr, $attributes);
last SWITCH;
};
$setDeviceAttr && do {
$rc = setDeviceAttributes($setDeviceAttr, $attributes);
last SWITCH;
};
$setDriverAttr && do {
$rc = setDriverAttributes($setDriverAttr, $attributes, FALSE);
last SWITCH;
};
$setTargetAttr && do {
$rc = setTargetAttributes($setTargetAttr, $driver, $attributes, FALSE);
last SWITCH;
};
$setLunAttr && do {
$rc = setLunAttributes($setLunAttr, $driver, $target, $attributes, $group);
last SWITCH;
};
$setInitiatorAttr && do {
$rc = setInitiatorAttributes($setInitiatorAttr, $driver, $target, $group, $attributes);
last SWITCH;
};
$openDev && do {
$rc = openDevice($openDev, $handler, $attributes);
last SWITCH;
};
$closeDev && do {
$rc = closeDevice($closeDev, $handler, $force);
last SWITCH;
};
$resyncDev && do {
$rc = resyncDevice($resyncDev);
last SWITCH;
};
$addGroup && do {
$rc = addGroup($addGroup, $driver, $target);
last SWITCH;
};
$removeGroup && do {
$rc = removeGroup($removeGroup, $driver, $target, $force);
last SWITCH;
};
$addInitiator && do {
$rc = addInitiator($addInitiator, $driver, $target, $group);
last SWITCH;
};
$removeInitiator && do {
$rc = removeInitiator($removeInitiator, $driver, $target, $group);
last SWITCH;
};
$moveInitiator && do {
$rc = moveInitiator($moveInitiator, $driver, $target, $group, $to);
last SWITCH;
};
$clearInitiators && do {
$rc = clearInitiators($driver, $target, $group);
last SWITCH;
};
$addLun && do {
$rc = addLun($addLun, $driver, $target, $device, $attributes, $group);
last SWITCH;
};
$removeLun && do {
$rc = removeLun($removeLun, $driver, $target, $device, $group);
last SWITCH;
};
$replaceLun && do {
$rc = replaceLun($replaceLun, $driver, $target, $group, $device, $attributes);
last SWITCH;
};
$clearLuns && do {
$rc = clearLuns($driver, $target, $group);
last SWITCH;
};
$enableTarget && do {
$rc = enableTarget($enableTarget);
last SWITCH;
};
$disableTarget && do {
$rc = disableTarget($disableTarget);
last SWITCH;
};
$issueLip && do {
$rc = issueLip();
last SWITCH;
};
if (!$all_good) {
print "No valid operations specified.\n";
usage();
exit TRUE;
}
}
print "\nAll done.\n";
exit $rc;
}
sub readWorkingConfig {
print "\nCollecting current configuration: ";
%CURRENT = ();
# Get current handlers/devices
my $handlers = $SCST->handlers();
immediateExit($SCST->errorString());
foreach my $handler (@{$handlers}) {
my $devices = $SCST->devicesByHandler($handler);
immediateExit($SCST->errorString());
$CURRENT{'handler'}->{$handler} = $devices;
}
# Get current assignments
my $drivers = $SCST->drivers();
immediateExit($SCST->errorString());
foreach my $driver (@{$drivers}) {
my %empty;
$CURRENT{'assign'}->{$driver} = \%empty;
my $targets = $SCST->targets($driver);
immediateExit($SCST->errorString());
foreach my $target (@{$targets}) {
my %empty;
$CURRENT{'assign'}->{$driver}->{$target} = \%empty;
my $luns = $SCST->luns($driver, $target);
$CURRENT{'assign'}->{$driver}->{$target}->{'LUN'} = $luns if (defined($luns));
my $groups = $SCST->groups($driver, $target);
immediateExit($SCST->errorString());
foreach my $group (@{$groups}) {
$CURRENT{'assign'}->{$driver}->{$target}->{'GROUP'}->{$group}->{'INITIATORS'} =
$SCST->initiators($driver, $target, $group);
immediateExit($SCST->errorString());
$CURRENT{'assign'}->{$driver}->{$target}->{'GROUP'}->{$group}->{'LUN'} =
$SCST->luns($driver, $target, $group);
immediateExit($SCST->errorString());
}
}
}
print "done.\n\n";
}
sub writeConfiguration {
my $file = shift;
my $nonkey = shift;
if (-f $file) {
if (!unlink $file) {
print "Failed to save current configuration, specified ".
"file exists and cannot be deleted.\n";
return TRUE;
}
}
my $io = new IO::File $file, O_CREAT|O_WRONLY;
if (!$io) {
print "Failed to save configuration to file '$file': $!\n";
return 1;
}
print "Writing current configuration to file '$file'.. ";
print $io "# Automatically generated by $Version.\n\n";
my $attributes = $SCST->scstAttributes();
immediateExit($SCST->errorString());
foreach my $attribute (sort keys %{$attributes}) {
next if (defined($$attributes{$attribute}->{'set'}));
if (!$$attributes{$attribute}->{'static'}) {
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (@{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
print $io "\t$attribute $value\n"
if (defined($value) && ($value ne ''));
}
} elsif ($nonkey) {
my $value = $$attributes{$attribute}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
print $io "$attribute $value\n"
if (defined($value) && ($value ne ''));
}
}
}
print $io "\n";
foreach my $handler (sort keys %{$CURRENT{'handler'}}) {
my $handler_buff;
my $handler_buff_nk;
my $handler_attrs = $SCST->deviceCreateAttributes($handler);
$attributes = $SCST->handlerAttributes($handler);
foreach my $attribute (sort keys %{$attributes}) {
next if (defined($$attributes{$attribute}->{'set'}));
if (!$$attributes{$attribute}->{'static'}) {
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (@{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
$handler_buff .= "\t$attribute $value\n" if (defined($value));
}
} elsif (($attribute eq 'enabled') || $nonkey) {
my $value = $$attributes{$attribute}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
if ($attribute eq 'enabled') {
$handler_buff .= "\t$attribute $value\n" if (defined($value));
} else {
$handler_buff_nk .= "\t$attribute $value\n" if (defined($value));
}
}
}
}
my $devices = $CURRENT{'handler'}->{$handler};
my $device_buff;
foreach my $device (@{$devices}) {
$device_buff .= "\tDEVICE $device";
$attributes = $SCST->deviceAttributes($device);
my $attribute_buff;
my $attribute_buff_nk;
foreach my $attribute (sort keys %{$attributes}) {
next if (defined($$attributes{$attribute}->{'set'}));
if (!defined($$handler_attrs{$attribute})) {
if (!$$attributes{$attribute}->{'static'}) {
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (@{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
$attribute_buff .= "\t\t$attribute $value\n"
if (defined($value));
}
} elsif (($attribute eq 'enabled') || $nonkey) {
my $value = $$attributes{$attribute}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
if ($attribute eq 'enabled') {
$attribute_buff .= "\t\t$attribute $value\n"
if (defined($value));
} else {
$attribute_buff_nk .= "\t\t$attribute $value\n"
if (defined($value));
}
}
}
}
}
$attribute_buff .= "\n" if ($attribute_buff);
$attribute_buff_nk .= "\n" if ($attribute_buff_nk);
if (!defined($$attributes{'scsi_device'})) {
my $create_buff;
foreach my $attribute (sort keys %{$attributes}) {
next if (defined($$attributes{$attribute}->{'set'}));
if (defined($$handler_attrs{$attribute})) {
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (keys %{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
$create_buff .= "\t\t\t$attribute $value\n"
if (defined($value));
}
# Shouldn't be any non-key create attributes
}
}
}
if ($create_buff) {
$attribute_buff .= "\t\tCREATE_ATTRIBUTES {\n";
$attribute_buff .= $create_buff;
$attribute_buff .= "\t\t}\n";
}
}
if ($attribute_buff_nk) {
$attribute_buff .= "\t\t# Non-key attributes\n";
$attribute_buff .= $attribute_buff_nk;
}
$attribute_buff =~ s/\n+$/\n/;
if ($attribute_buff) {
$device_buff .= " {\n";
$device_buff .= $attribute_buff;
$device_buff .= "\t}\n\n";
} else {
$device_buff .= "\n";
}
}
$device_buff =~ s/\n+$/\n/;
$handler_buff .= $device_buff;
if ($handler_buff_nk) {
$handler_buff .= "\t# Non-key attributes\n";
$handler_buff .= $handler_buff_nk;
}
if ($handler_buff) {
print $io "HANDLER $handler {\n";
print $io $handler_buff;
print $io "}\n\n";
}
}
foreach my $driver (sort keys %{$CURRENT{'assign'}}) {
my $driver_buff;
my $drv_attrs = $SCST->driverAttributes($driver);
my $drv_attr_buff;
my $drv_attr_buff_nk;
foreach my $attr (keys %{$drv_attrs}) {
next if ($$drv_attrs{$attr}->{'static'});
next if ($$drv_attrs{$attr}->{'set'});
if (defined($$drv_attrs{$attr}->{'keys'})) {
foreach my $key (keys %{$$drv_attrs{$attr}->{'keys'}}) {
my $value = $$drv_attrs{$attr}->{'keys'}->{$key}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
$drv_attr_buff .= "\t$attr $value\n"
if (defined($value));
}
} elsif (($attr eq 'enabled') || $nonkey) {
my $value = $$drv_attrs{$attr}->{'value'};
$value = "\"$value\"" if ($value =~ /\s/);
if ($attr eq 'enabled') {
$drv_attr_buff .= "\t$attr $value\n"
if (defined($value));
} else {
$drv_attr_buff_nk .= "\t$attr $value\n"
if (defined($value));
}
}
}
$drv_attr_buff .= "\n" if ($drv_attr_buff);
$drv_attr_buff_nk .= "\n" if ($drv_attr_buff_nk);
my $targets = $CURRENT{'assign'}->{$driver};
my $target_buff;
foreach my $target (sort keys %{$targets}) {
$target_buff .= "\tTARGET $target";
my $tgt_attrs = $SCST->targetAttributes($driver, $target);
my $attribute_buff;
my $attribute_buff_nk;
foreach my $attr (keys %{$tgt_attrs}) {
next if ($$tgt_attrs{$attr}->{'static'});
next if ($$tgt_attrs{$attr}->{'set'});
if (defined($$tgt_attrs{$attr}->{'keys'})) {
foreach my $key (keys %{$$tgt_attrs{$attr}->{'keys'}}) {
my $value = $$tgt_attrs{$attr}->{'keys'}->{$key}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
$attribute_buff .= "\t\t$attr $value\n"
if (defined($value));
}
} elsif (($attr eq 'enabled') || $nonkey) {
my $value = $$tgt_attrs{$attr}->{'value'};
$value = "\"$value\"" if ($value =~ /\s/);
if ($attr eq 'enabled') {
$attribute_buff .= "\t\t$attr $value\n"
if (defined($value));
} else {
$attribute_buff_nk .= "\t\t$attr $value\n"
if (defined($value));
}
}
}
$attribute_buff .= "\n" if ($attribute_buff);
$attribute_buff_nk .= "\n" if ($attribute_buff_nk);
my $luns = $CURRENT{'assign'}->{$driver}->{$target}->{'LUN'};
my $lun_attrs = $SCST->lunCreateAttributes($driver, $target);
my $t_lun_buff;
foreach my $lun (sort numerically keys %{$luns}) {
my $lun_dev = $$luns{$lun};
$t_lun_buff .= "\t\tLUN $lun $lun_dev";
$attributes = $SCST->lunAttributes($driver, $target, $lun);
my $l_attribute_buff;
my $l_attribute_buff_nk;
foreach my $attribute (sort keys %{$attributes}) {
next if (defined($$attributes{$attribute}->{'set'}));
if (!$$attributes{$attribute}->{'static'} ||
defined($$lun_attrs{$attribute})) {
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (keys %{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
$l_attribute_buff .= "\t\t\t$attribute $value\n"
if (defined($value));
}
} elsif (($attribute eq 'enabled') || $nonkey) {
my $value = $$attributes{$attribute}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
if (defined($$lun_attrs{$attribute})) {
$l_attribute_buff .= "\t\t\t$attribute $value\n"
if (defined($value));
} elsif ($attribute eq 'enabled') {
$l_attribute_buff .= "\t\t\t$attribute $value\n"
if (defined($value));
} else {
$l_attribute_buff_nk .= "\t\t\t$attribute $value\n"
if (defined($value));
}
}
}
}
if ($l_attribute_buff_nk) {
$l_attribute_buff .= "\t\t\t\t# Non-key attributes\n";
$l_attribute_buff .= $l_attribute_buff_nk;
}
if ($l_attribute_buff) {
$t_lun_buff .= " {\n";
$t_lun_buff .= $l_attribute_buff;
$t_lun_buff .= "\t\t}\n\n";
} else {
$t_lun_buff .= "\n";
}
}
my $groups = $CURRENT{'assign'}->{$driver}->{$target}->{'GROUP'};
my $group_buff;
foreach my $group (sort keys %{$groups}) {
my $lun_attrs = $SCST->lunCreateAttributes($driver, $target, $group);
my $ini_attrs = $SCST->initiatorCreateAttributes($driver, $target, $group);
$group_buff .= "\t\tGROUP $group";
my $luns = $CURRENT{'assign'}->{$driver}->{$target}->{'GROUP'}->{$group}->{'LUN'};
my $lun_buff;
foreach my $lun (sort numerically keys %{$luns}) {
my $lun_dev = $$luns{$lun};
$lun_buff .= "\t\t\tLUN $lun $lun_dev";
$attributes = $SCST->lunAttributes($driver, $target, $lun, $group);
my $l_attribute_buff;
my $l_attribute_buff_nk;
foreach my $attribute (sort keys %{$attributes}) {
next if (defined($$attributes{$attribute}->{'set'}));
if (!$$attributes{$attribute}->{'static'} ||
defined($$lun_attrs{$attribute})) {
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (keys %{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
$l_attribute_buff .= "\t\t\t\t$attribute $value\n"
if (defined($value));
}
} elsif (($attribute eq 'enabled') || $nonkey) {
my $value = $$attributes{$attribute}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
if (defined($$lun_attrs{$attribute})) {
$l_attribute_buff .= "\t\t\t\t$attribute $value\n"
if (defined($value));
} elsif ($attribute eq 'enabled') {
$l_attribute_buff .= "\t\t\t\t$attribute $value\n"
if (defined($value));
} else {
$l_attribute_buff_nk .= "\t\t\t\t$attribute $value\n"
if (defined($value));
}
}
}
}
if ($l_attribute_buff_nk) {
$l_attribute_buff .= "\t\t\t\t# Non-key attributes\n";
$l_attribute_buff .= $l_attribute_buff_nk;
}
if ($l_attribute_buff) {
$lun_buff .= " {\n";
$lun_buff .= $l_attribute_buff;
$lun_buff .= "\t\t\t}\n\n";
} else {
$lun_buff .= "\n";
}
}
my $inits = $CURRENT{'assign'}->{$driver}->{$target}->{'GROUP'}->{$group}->{'INITIATORS'};
my $init_buff;
foreach my $init (@{$inits}) {
$init_buff .= "\t\t\tINITIATOR $init";
$attributes = $SCST->initiatorAttributes($driver, $target, $group, $init);
my $i_attribute_buff;
my $i_attribute_buff_nk;
foreach my $attribute (sort keys %{$attributes}) {
next if (defined($$attributes{$attribute}->{'set'}));
if (!$$attributes{$attribute}->{'static'} ||
defined($$ini_attrs{$attribute})) {
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (keys %{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
$i_attribute_buff .= "\t\t\t\t$attribute $value\n"
if (defined($value));
}
} elsif (($attribute eq 'enabled') || $nonkey) {
my $value = $$attributes{$attribute}->{'value'};
$value = "\"$value\"" if ($value =~ / /);
if ($attribute eq 'enabled') {
$i_attribute_buff .= "\t\t\t\t$attribute $value\n"
if (defined($value));
} else {
$i_attribute_buff_nk .= "\t\t\t\t$attribute $value\n"
if (defined($value));
}
}
}
}
if ($i_attribute_buff_nk) {
$i_attribute_buff .= "\t\t\t\t# Non-key attributes\n";
$i_attribute_buff .= $i_attribute_buff_nk;
}
if ($i_attribute_buff) {
$init_buff .= " {\n";
$init_buff .= i_$attribute_buff;
$init_buff .= "\t\t\t}\n";
} else {
$init_buff .= "\n";
}
$init_buff .= "\n";
}
$init_buff =~ s/\n\n$/\n/;
if ($lun_buff || $init_buff) {
$group_buff .= " {\n";
if ($lun_buff) {
$group_buff .= $lun_buff;
}
if ($init_buff) {
$group_buff .= $init_buff;
}
$group_buff =~ s/\n\n$/\n/;
$group_buff .= "\t\t}\n\n";
}
$group_buff .= "\n";
$group_buff =~ s/\n\n$/\n/;
}
$group_buff .= "\n" if ($group_buff);
$group_buff =~ s/\n+$/\n/;
if ($attribute_buff_nk) {
$attribute_buff .= "\t\t# Non-key attributes\n";
$attribute_buff .= $attribute_buff_nk;
}
if ($attribute_buff || $t_lun_buff || $group_buff ) {
$target_buff .= " {\n";
$target_buff .= $attribute_buff;
$target_buff .= $t_lun_buff;
$target_buff .= $group_buff;
$target_buff =~ s/\n\n$/\n/;
$target_buff .= "\t}\n\n";
} else {
$target_buff .= "\n";
}
}
if ($drv_attr_buff_nk) {
$drv_attr_buff .= "\t# Non-key attributes\n";
$drv_attr_buff .= $drv_attr_buff_nk;
}
$driver_buff .= $drv_attr_buff;
$driver_buff .= $target_buff;
$driver_buff =~ s/\n\n$/\n/;
if ($driver_buff) {
print $io "TARGET_DRIVER $driver {\n";
print $io $driver_buff;
print $io "}\n\n";
}
}
close $io;
return FALSE;
}
sub checkConfiguration {
my $file = shift;
my $no_drivers;
my $no_handlers;
print "-> Checking configuration file '$file' for errors.\n";
$CONFIG = readConfig($file) if (!$CONFIG);
# Check for a minimum sane configuration
if (!defined($$CONFIG{'TARGET_DRIVER'}) ||
!(scalar keys %{$$CONFIG{'TARGET_DRIVER'}})) {
print "\t-> WARNING: No TARGET_DRIVER section defined. ".
"No target drivers will be configured.\n\n";
$no_drivers = TRUE;
}
if (!defined($$CONFIG{'HANDLER'}) ||
!(scalar keys %{$$CONFIG{'HANDLER'}})) {
print "\t-> WARNING: No HANDLER section defined. ".
"Only physical media will be configured for targets.\n\n";
$no_handlers = TRUE;
}
if ($no_drivers && $no_handlers) {
immediateExit("No target drivers or handlers defined, aborting!");
}
if (!$no_drivers) {
foreach my $driver (keys %{$$CONFIG{'TARGET_DRIVER'}}) {
my $no_targets;
if (!defined($CURRENT{'assign'}->{$driver})) {
print "\t-> WARNING: Target driver '$driver' is not loaded or available.\n\n";
next;
}
if (!defined($$CONFIG{'TARGET_DRIVER'}->{$driver}->{'TARGET'}) ||
!(scalar keys %{$$CONFIG{'TARGET_DRIVER'}->{$driver}->{'TARGET'}})) {
print "\t-> WARNING: Driver '$driver' has no configured targets.\n\n";
$no_targets = TRUE;
}
if (!$no_targets) {
foreach my $target (keys %{$$CONFIG{'TARGET_DRIVER'}->{$driver}->{'TARGET'}}) {
if (!defined($CURRENT{'assign'}->{$driver}->{$target})) {
if (!$SCST->driverIsVirtualCapable($driver)) {
print "\t-> FATAL: Target '$target' for driver '$driver' ".
"does not exist.\n";
return TRUE;
}
}
}
}
}
}
my %cdevices;
foreach my $handler (sort keys %{$$CONFIG{'HANDLER'}}) {
foreach my $device (sort keys %{$$CONFIG{'HANDLER'}->{$handler}->{'DEVICE'}}) {
# Since some people may get confused with how to open
# a vcdrom, we'll support having '/dev/cdrom' instead of just 'cdrom'.
if ($device =~ /^\/dev\//) {
my $_device = $device;
$_device =~ s/^\/dev\///o;
my $tree = $$CONFIG{'HANDLER'}->{$handler}->{'DEVICE'}->{$device};
print "\t-> WARNING: Device '$device' configured for handler '$handler' may ".
"not contain the full /dev path, please change to '$_device'.\n\n";
delete $$CONFIG{'HANDLER'}->{$handler}->{'DEVICE'}->{$device};
$$CONFIG{'HANDLER'}->{$handler}->{'DEVICE'}->{$_device} = $tree;
} elsif ($device =~ /\//) {
print "\t-> FATAL: Device '$device' configured for handler '$handler' may not ".
"contain character '/'.\n";
return TRUE;
}
$cdevices{$device}++;
}
}
foreach my $driver (keys %{$$CONFIG{'TARGET_DRIVER'}}) {
foreach my $target (keys %{$$CONFIG{'TARGET_DRIVER'}->{$driver}->{'TARGET'}}) {
my $tgt = $$CONFIG{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target};
if (defined($$tgt{'LUN'})) {
foreach my $lun (keys %{$$tgt{'LUN'}}) {
foreach my $device (keys %{$$tgt{'LUN'}->{$lun}}) {
if (!defined($cdevices{$device})) {
print "\t-> WARNING: Device '$device' associated with driver/target ".
"'$driver/$target' at LUN $lun is not defined within configuration, ".
"removing it.\n\n";
delete $$tgt{'LUN'}->{$lun};
}
}
}
}
if (defined($$tgt{'GROUP'})) {
foreach my $group (keys %{$$tgt{'GROUP'}}) {
if (defined($$tgt{'GROUP'}->{$group}->{'LUN'})) {
foreach my $lun (keys %{$$tgt{'GROUP'}->{$group}->{'LUN'}}) {
foreach my $device (keys %{$$tgt{'GROUP'}->{$group}->{'LUN'}->{$lun}}) {
if (!defined($cdevices{$device})) {
print "\t-> WARNING: Device '$device' associated with ".
"driver/target '$driver/$target' at LUN $lun is not ".
"defined within configuration, removing it.\n\n";
delete $$tgt{'GROUP'}->{$group}->{'LUN'}->{$lun};
}
}
}
}
}
}
}
}
return FALSE;
}
sub applyConfiguration {
my $file = shift;
my $force = shift;
$CONFIG = readConfig($file) if (!$CONFIG);
# Apply config deletions
if ($force) {
applyConfigAssignments($CONFIG, $force, TRUE);
readWorkingConfig();
}
# Apply config additions
applyConfigDevices($CONFIG, $force);
applyConfigAssignments($CONFIG, $force);
# And SCST attributes..
my %_attributes;
foreach my $item (keys %{$CONFIG}) {
next if ($item eq 'HANDLER');
next if ($item eq 'TARGET_DRIVER');
$_attributes{$item} = $$CONFIG{$item};
}
my $attributes = configToAttr(\%_attributes);
setScstAttributes($attributes);
}
sub applyConfigDevices {
my $config = shift;
my $deletions = shift;
my $handlers = $CURRENT{'handler'};
foreach my $handler (keys %{$handlers}) {
foreach my $device (@{$$handlers{$handler}}) {
if (!defined($$config{'HANDLER'}) ||
!defined($$config{'HANDLER'}->{$handler}) ||
!defined($$config{'HANDLER'}->{$handler}->{'DEVICE'}) ||
!defined($$config{'HANDLER'}->{$handler}->{'DEVICE'}->{$device})) {
my $attributes = $SCST->deviceAttributes($device);
next if (defined($$attributes{'scsi_device'}));
if ($deletions) {
closeDevice($device, $handler, $deletions);
} else {
print "-> Device '$device' is not in configuration. Use -force to close it.\n";
}
}
}
}
$handlers = $$config{'HANDLER'};
foreach my $handler (sort keys %{$handlers}) {
if (defined($$handlers{$handler}->{'DEVICE'})) {
my $devices = $$handlers{$handler}->{'DEVICE'};
foreach my $device (sort keys %{$devices}) {
next if (handlerHasDevice($handler, $device));
my $attributes = configToAttr($$devices{$device}->{'CREATE_ATTRIBUTES'});
openDevice($device, $handler, $attributes);
}
}
}
}
sub applyConfigAssignments {
my $config = shift;
my $deletions = shift;
my $only_del = shift;
my $assignments = $CURRENT{'assign'};
foreach my $driver (keys %{$assignments}) {
foreach my $target (keys %{$$assignments{$driver}}) {
my $luns = $$assignments{$driver}->{$target}->{'LUN'};
my $def_group = $$config{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target};
foreach my $lun (keys %{$luns}) {
my $device = $$luns{$lun};
if (!defined($$def_group{'LUN'}->{$lun}->{$device})) {
if ($deletions) {
removeLun($lun, $driver, $target, $device);
} else {
print "-> Device '$device' at LUN '$lun' is not in configuration ".
"for driver/target '$driver/$target'. ".
"Use -force to remove it.\n";
}
}
}
foreach my $group (keys %{$$assignments{$driver}->{$target}->{'GROUP'}}) {
my $luns = $$assignments{$driver}->{$target}->{'GROUP'}->{$group}->{'LUN'};
my $inits = $$assignments{$driver}->{$target}->{'GROUP'}->{$group}->{'INITIATORS'};
my $def_group = $$config{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'GROUP'}->{$group};
foreach my $lun (keys %{$luns}) {
my $device = $$luns{$lun};
if (!defined($$def_group{'LUN'}->{$lun}->{$device})) {
if ($deletions) {
removeLun($lun, $driver, $target, $device, $group);
} else {
print "-> Device '$device' at LUN '$lun' is not in configuration ".
"for driver/target/group '$driver/$target/$group'. ".
"Use -force to remove it.\n";
}
}
}
foreach my $init (@{$inits}) {
if (!defined($$def_group{'INITIATOR'}->{$init})) {
if ($deletions) {
removeInitiator($init, $driver, $target, $group);
} else {
print "-> Initiator '$init' is not in configuration ".
"for driver/target/group '$driver/$target/$group'. ".
"Use -force to remove it.\n";
}
}
}
if (!defined($$config{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'GROUP'}->{$group})) {
if ($deletions) {
removeGroup($group, $driver, $target);
} else {
print "-> Group '$group' is not in configuration. Use -force to remove.\n";
}
next;
}
}
}
}
return if ($only_del);
$assignments = $$config{'TARGET_DRIVER'};
foreach my $driver (sort keys %{$assignments}) {
if (!defined($CURRENT{'assign'}->{$driver})) {
immediateExit("Target driver '$driver' is not loaded or available.");
}
my %_attributes;
foreach my $item (keys %{$$assignments{$driver}}) {
if ($item eq 'TARGET') {
applyTargetAssignments($driver, $$assignments{$driver}->{$item},
$deletions);
} else {
$_attributes{$item} = $$assignments{$driver}->{$item};
}
}
my $attributes = configToAttr(\%_attributes);
setDriverAttributes($driver, $attributes, $deletions) if (scalar keys %{$attributes});
}
}
sub applyTargetAssignments {
my $driver = shift;
my $targets = shift;
my $deletions = shift;
foreach my $target (sort keys %{$targets}) {
if (!defined($CURRENT{'assign'}->{$driver}->{$target})) {
if (!$SCST->driverIsVirtualCapable($driver)) {
immediateExit("Target '$target' for driver '$driver' does not exist.");
} else {
# TODO: Add $attributes
print "-> Creating target '$target' for driver '$driver': ";
my $rc = $SCST->addVirtualTarget($driver, $target);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
}
my %_attributes;
foreach my $item (keys %{$$targets{$target}}) {
if ($item eq 'GROUP') {
applyGroupAssignments($driver, $target, $$targets{$target}->{$item});
} elsif ($item eq 'LUN') {
applyLunAssignments($driver, $target, undef, $$targets{$target}->{$item});
} else {
$_attributes{$item} = $$targets{$target}->{$item};
}
}
my $attributes = configToAttr(\%_attributes);
setTargetAttributes($target, $driver, $attributes, $deletions);
}
}
sub applyGroupAssignments {
my $driver = shift;
my $target = shift;
my $groups = shift;
foreach my $group (sort keys %{$groups}) {
if (!defined($CURRENT{'assign'}->{$driver}->{$target}->{'GROUP'}->{$group})) {
addGroup($group, $driver, $target);
}
my %_attributes;
foreach my $item (keys %{$$groups{$group}}) {
if ($item eq 'LUN') {
applyLunAssignments($driver, $target, $group,
$$groups{$group}->{$item});
} elsif ($item eq 'INITIATOR') {
applyInitiatorAssignments($driver, $target, $group,
$$groups{$group}->{$item});
} else {
$_attributes{$item} = $$groups{$group}->{$item};
}
}
my $attributes = configToAttr(\%_attributes);
setGroupAttributes($target, $driver, $group, $attributes);
}
}
sub applyLunAssignments {
my $driver = shift;
my $target = shift;
my $group = shift;
my $luns = shift;
my $c_luns;
if ($group) {
$c_luns = $CURRENT{'assign'}->{$driver}->{$target}->{'GROUP'}->{$group}->{'LUN'};
} else {
$c_luns = $CURRENT{'assign'}->{$driver}->{$target}->{'LUN'};
}
foreach my $lun (sort keys %{$luns}) {
if (!defined($$c_luns{$lun})) {
if ((scalar keys %{$$luns{$lun}}) > 1) {
immediateExit("Invalid configuration encountered. ".
"Driver/target/group/lun $driver/$target/$group/$lun ".
"has multiple devices assigned.");
}
foreach my $device (sort keys %{$$luns{$lun}}) {
my $attributes = configToAttr($$luns{$lun}->{$device});
addLun($lun, $driver, $target, $device, $attributes, $group);
}
}
}
}
sub applyInitiatorAssignments {
my $driver = shift;
my $target = shift;
my $group = shift;
my $initiators = shift;
my $c_inits = $CURRENT{'assign'}->{$driver}->{$target}->{'GROUP'}->{$group}->{'INITIATORS'};
foreach my $initiator (sort keys %{$initiators}) {
if (!groupHasInitiator($c_inits, $initiator)) {
addInitiator($initiator, $driver, $target, $group);
}
}
}
sub clearConfiguration {
my $noprompt = shift;
my $force = shift;
my $assignments = $CURRENT{'assign'};
foreach my $driver (sort keys %{$assignments}) {
foreach my $target (sort keys %{$$assignments{$driver}}) {
foreach my $group (sort keys %{$$assignments{$driver}->{$target}->{'GROUP'}}) {
clearInitiators($driver, $target, $group);
clearLuns($driver, $target, $group);
removeGroup($group, $driver, $target, $force);
}
clearLuns($driver, $target);
removeTargetDynamicAttributes($driver, $target);
if ($SCST->targetType($driver, $target) == $SCST::SCST::TGT_TYPE_VIRTUAL) {
removeVirtualTarget($driver, $target);
}
}
removeDriverDynamicAttributes($driver);
}
my $handlers = $CURRENT{'handler'};
foreach my $handler (sort keys %{$handlers}) {
foreach my $device (@{$$handlers{$handler}}) {
my $attributes = $SCST->deviceAttributes($device);
if (!defined($$attributes{'scsi_device'})) {
closeDevice($device, $handler, $force);
}
}
}
# Todo - check return code
# TODO: should we disable all target drivers as well?
}
sub removeVirtualTarget {
my $driver = shift;
my $target = shift;
print "-> Removing virtual target '$target' from driver '$driver': ";
my $rc = $SCST->removeVirtualTarget($driver, $target);
print "done.\n";
# Todo - check return code
}
####################################################################
sub listHandlers {
my $handler = shift;
return listHandler($handler) if ($handler);
my $handlers = $SCST->handlers();
my $l_handler;
foreach my $handler (@{$handlers}) {
$l_handler = length($handler) if ($l_handler < length($handler));
}
print "\tHandler\n";
print "\t";
for (my $x = 0; $x < $l_handler; $x++) {
print "-";
};
print "\n";
foreach my $handler (@{$handlers}) {
print "\t$handler\n";
}
}
sub listHandler {
my $handler = shift;
my $devices = $SCST->devicesByHandler($handler);
if ($#{$devices} > -1) {
my $l_device;
foreach my $device (@{$devices}) {
$l_device = length($device) if ($l_device < length($device));
}
printf("\t%-*s %-*s\n", length($handler), 'Handler', $l_device, 'Device');
print "\t";
for (my $x = 0; $x < (length($handler) + $l_device + 2); $x++) {
print "-";
};
print "\n";
my $first = TRUE;
foreach my $device (@{$devices}) {
if ($first) {
printf("\t%-*s %-*s\n", length($handler), $handler, $l_device, $device);
$first = FALSE;
} else {
printf("\t%-*s %-*s\n", length($handler), '', $l_device, $device);
}
}
} else {
print "\t(handler '$handler' has no assigned devices)\n";
}
}
sub listDevices {
my $device = shift;
listDevice($device) if ($device);
}
sub listDevice {
my $device = shift;
}
sub listDrivers {
my $driver = shift;
return listTargets(undef, $driver) if ($driver);
my $drivers = $SCST->drivers();
my $l_driver;
foreach my $driver (@{$drivers}) {
$l_driver = length($driver) if ($l_driver < length($driver));
}
print "\tDriver\n";
print "\t";
for (my $x = 0; $x < $l_driver; $x++) {
print "-";
}
print "\n";
foreach my $driver (@{$drivers}) {
print "\t$driver\n";
}
}
sub listTargets {
my $target = shift;
my $driver = shift;
return listGroups(undef, $driver, $target) if ($target && $driver);
my $drivers = $SCST->drivers();
my $l_driver;
my $l_target;
foreach my $driver (@{$drivers}) {
$l_driver = length($driver) if ($l_driver < length($driver));
my $targets = $SCST->targets($driver);
foreach my $target (@{$targets}) {
$l_target = length($target) if ($l_target < length($target));
}
}
printf("\t%-*s %-*s\n", $l_driver, 'Driver', $l_target, 'Target');
print "\t";
for (my $x = 0; $x < ($l_driver + $l_target + 1); $x++) {
print "-";
}
print "\n";
my %p;
foreach my $driver (@{$drivers}) {
my $targets = $SCST->targets($driver);
foreach my $target (@{$targets}) {
if (!defined($p{$driver})) {
printf("\t%-*s %-*s\n", $l_driver, $driver, $l_target, $target);
$p{$driver}++;
} else {
printf("\t%-*s %-*s\n", $l_driver, '', $l_target, $target);
}
}
}
}
sub listSessions {
}
sub listGroup {
my $driver = shift;
my $target = shift;
my $group = shift;
my $luns = shift;
my $initiators = shift;
$luns = $SCST->luns($driver, $target, $group) if (!$luns);
$initiators = $SCST->initiators($driver, $target, $group) if (!$initiators);
if ((keys %{$luns}) || ($#{$initiators} > -1)) {
my $l_device;
my $l_initiator;
foreach my $lun (keys %{$luns}) {
$l_device = length($$luns{$lun}) if (length($$luns{$lun}) > $l_device);
}
foreach my $initiator (@{$initiators}) {
$l_initiator = length($initiator) if (length($initiator) > $l_initiator);
}
print "Assigned LUNs:\n\n";
if (keys %{$luns}) {
printf("\t%-4s %-*s\n", 'LUN', $l_device, 'Device');
print "\t";
for (my $x = 0; $x < ($l_device + 5); $x++) {
print "-";
}
print "\n";
foreach my $lun (sort keys %{$luns}) {
my $device = $$luns{$lun};
printf("\t%-4s %-*s\n", $lun, $l_device, $$luns{$lun});
}
} else {
print "\t(none)\n";
}
print "\nAssigned Initiators:\n\n";
if ($#{$initiators} > -1) {
print "\tInitiator\n";
print "\t";
for (my $x = 0; $x < $l_initiator; $x++) {
print "-";
}
print "\n";
foreach my $initiator (@{$initiators}) {
print "\t$initiator\n";
}
} else {
print "\t(none)\n";
}
} else {
print "Group '$group' has no associated LUNs or initiators.\n";
}
}
sub listGroups {
my $group = shift;
my $driver = shift;
my $target = shift;
if ($group && $driver && $target) {
return listGroup($driver, $target, $group);
}
my $drivers = $SCST->drivers();
foreach my $driver (@{$drivers}) {
my $targets = $SCST->targets($driver);
foreach my $target (@{$targets}) {
my $groups = $SCST->groups($driver, $target);
foreach my $group (@{$groups}) {
print "Driver: $driver\n";
print "Target: $target\n";
print "Group : $group\n\n";
listGroup($driver, $target, $group);
print "\n\n";
}
}
}
}
sub listExported {
my $device = shift;
my $attributes = shift;
$attributes = $SCST->deviceAttributes($device) if (!$attributes);
if (keys %{$$attributes{'exported'}}) {
my $exported = $$attributes{'exported'}->{'value'};
my $l_driver;
my $l_target;
my $l_group;
foreach my $driver (keys %{$exported}) {
$l_driver = length($driver)
if (length($driver) > $l_driver);
foreach my $target (keys %{$$exported{$driver}}) {
$l_target = length($target)
if (length($target) > $l_target);
foreach my $group (keys %{$$exported{$driver}->{$target}}) {
$l_group = length($group)
if (length($group) > $l_group);
}
}
}
print "Device '$device' is currently in use by the following:\n\n";
printf("\t%-*s %-*s %-*s %-4s\n", $l_driver, 'Driver', $l_target, 'Target',
$l_group, 'Group', 'Lun');
print "\t";
for (my $x = 0; $x < ($l_driver + $l_target + $l_group + 5); $x++) {
print "-";
}
print "\n";
foreach my $driver (sort keys %{$exported}) {
foreach my $target (sort keys %{$$exported{$driver}}) {
foreach my $group (sort keys %{$$exported{$driver}->{$target}}) {
my $lun = $$exported{$driver}->{$target}->{$group};
printf("\t%-*s %-*s %-*s %-4s\n", $l_driver, $driver,
$l_target, $target, $l_group, $group, $lun);
}
}
}
} else {
print "Device '$device' is not currently in use by any group.\n";
}
}
sub listScstAttributes {
}
sub listHandlerAttributes {
my $handler = shift;
}
sub listDeviceAttributes {
my $device = shift;
my $l_attr;
my $l_val;
my $attributes = $SCST->deviceAttributes($device);
immediateExit($SCST->errorString());
foreach my $attribute (sort keys %{$attributes}) {
my $value = $$attributes{$attribute}->{'value'};
next if (ref($value));
$l_attr = length($attribute) if (length($attribute) > $l_attr);
$l_val = length($value) if (length($value) > $l_val);
}
print "Attributes for device '$device':\n\n";
printf("\t%-*s %-*s %-5s\n", $l_attr, 'Attribute', $l_val, 'Value', 'Static');
print "\t";
for (my $x = 0; $x < ($l_attr + $l_val + 8); $x++) {
print "-";
}
print "\n";
foreach my $attribute (sort keys %{$attributes}) {
my $value = $$attributes{$attribute}->{'value'};
my $static = $$attributes{$attribute}->{'static'};
next if (ref($value));
$value = '-' if (!defined($value));
$static = ($static ? 'Yes' : 'No');
printf("\t%-*s %-*s %-5s\n", $l_attr, $attribute, $l_val, $value, $static);
}
}
sub listDriverAttributes {
my $driver = shift;
}
sub listTargetAttributes {
my $target = shift;
my $driver = shift;
}
sub listLunAttributes {
my $lun = shift;
my $driver = shift;
my $target = shift;
my $group = shift;
}
sub listInitiatorAttributes {
my $initiator = shift;
my $driver = shift;
my $target = shift;
my $group = shift;
}
####################################################################
sub setScstAttributes {
my $attributes = shift;
my $_attributes = $SCST->scstAttributes();
foreach my $attribute (sort keys %{$attributes}) {
if (defined($$_attributes{$attribute}) &&
!$$_attributes{$attribute}->{'static'}) {
my $value = $$attributes{$attribute};
next if ($$_attributes{$attribute}->{'value'} eq $value);
print "-> Setting SCST attribute '$attribute' to '$value': ";
my $rc = $SCST->setScstAttribute($attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
} else {
print "-> WARNING: SCST lacks the settable ".
"attribute '$attribute', ignoring.\n\n";
}
}
}
sub setHandlerAttributes {
my $handler = shift;
my $attributes = shift;
my $_attributes = $SCST->handlerAttributes($handler);
foreach my $attribute (sort keys %{$attributes}) {
if (defined($$_attributes{$attribute}) &&
!$$_attributes{$attribute}->{'static'}) {
my $value = $$attributes{$attribute};
print "-> Setting handler attribute '$attribute' to '$value' for handler '$handler': ";
my $rc = $SCST->setHandlerAttribute($handler, $attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
} else {
print "-> WARNING: Handler '$handler' lacks the settable ".
"attribute '$attribute', ignoring.\n\n";
}
}
}
sub setDeviceAttributes {
my $device = shift;
my $attributes = shift;
my $_attributes = $SCST->deviceAttributes($device);
foreach my $attribute (sort keys %{$attributes}) {
if (defined($$_attributes{$attribute}) &&
!$$_attributes{$attribute}->{'static'}) {
my $value = $$attributes{$attribute};
next if ($$_attributes{$attribute}->{'value'} eq $value);
print "-> Setting device attribute '$attribute' to value '$value' for device '$device': ";
my $rc = $SCST->setDeviceAttribute($device, $attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
} else {
print "-> WARNING: Device '$device' lacks the settable ".
"attribute '$attribute', ignoring.\n\n";
}
}
}
sub setDriverAttribute {
my $driver = shift;
my $attribute = shift;
my $value = shift;
print "-> Setting driver attribute '$attribute' to value '$value' for driver '$driver': ";
my $rc = $SCST->setDriverAttribute($driver, $attribute, $value);
print "done.\n";
return $rc;
}
sub setDriverAttributes {
my $driver = shift;
my $attributes = shift;
my $deletions = shift;
my %toset;
my %existing;
my $driverCap = $SCST->driverIsVirtualCapable($driver);
my $_attributes = $SCST->driverAttributes($driver);
# build caches for easier matching
foreach my $attribute (keys %{$attributes}) {
if (ref($$attributes{$attribute}) eq 'ARRAY') {
foreach my $value (@{$$attributes{$attribute}}) {
$toset{$attribute}->{$value} = FALSE;
}
} else {
$toset{$attribute}->{$$attributes{$attribute}} = FALSE;
}
}
foreach my $attribute (keys %{$_attributes}) {
next if ($$_attributes{$attribute}->{'static'});
if (defined($$_attributes{$attribute}->{'keys'})) {
foreach my $key (keys %{$$_attributes{$attribute}->{'keys'}}) {
my $value = $$_attributes{$attribute}->{'keys'}->{$key}->{'value'};
$existing{$attribute}->{$value} = FALSE
if (defined($value) && ($value ne ''));
}
} else {
my $value = $$_attributes{$attribute}->{'value'};
$existing{$attribute}->{$value} = FALSE
if (defined($value) && ($value ne ''));
}
}
# add/change
foreach my $attribute (keys %toset) {
foreach my $value (keys %{$toset{$attribute}}) {
if (!defined($existing{$attribute}) &&
$driverCap && !$SCST->checkDriverDynamicAttributes($driver, $attribute)) {
addDriverDynamicAttribute($driver, $attribute, $value);
next;
}
# already set, move on
if (defined($existing{$attribute}->{$value})) {
$existing{$attribute}->{$value} = TRUE;
next;
}
# Set the existing attribute
if ($driverCap && !$SCST->checkDriverDynamicAttributes($driver, $attribute)) {
addDriverDynamicAttribute($driver, $attribute, $value);
} else {
setDriverAttribute($driver, $attribute, $value);
}
$existing{$attribute}->{$value} = TRUE;
}
}
foreach my $attribute (keys %existing) {
next if (!$driverCap || $SCST->checkDriverDynamicAttributes($driver, $attribute));
foreach my $value (keys %{$existing{$attribute}}) {
if (!$existing{$attribute}->{$value}) {
if ($deletions) {
removeDriverDynamicAttribute($driver, $attribute, $value);
} else {
print "-> Driver dynamic attribute '$attribute' with value '$value' ".
"is not in configuration. Use -force to remove it.\n";
}
}
}
}
}
sub addDriverDynamicAttribute {
my $driver = shift;
my $attribute = shift;
my $value = shift;
print "-> Attempting to add driver attribute '$attribute' with value '$value' for driver '$driver': ";
my $rc = $SCST->addDriverDynamicAttribute($driver, $attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub removeDriverDynamicAttribute {
my $driver = shift;
my $attribute = shift;
my $value = shift;
return if (!$SCST->driverIsVirtualCapable($driver));
print "-> Removing dynamic attribute '$attribute' with value '$value' for driver '$driver': ";
my $rc = $SCST->removeDriverDynamicAttribute($driver, $attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub setTargetAttribute {
my $target = shift;
my $driver = shift;
my $attribute = shift;
my $value = shift;
print "-> Setting target attribute '$attribute' to value '$value' for ".
"driver/target '$driver/$target': ";
my $rc = $SCST->setTargetAttribute($driver, $target, $attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub setTargetAttributes {
my $target = shift;
my $driver = shift;
my $attributes = shift;
my $deletions = shift;
my %toset;
my %existing;
my $driverCap = $SCST->driverIsVirtualCapable($driver);
my $_attributes = $SCST->targetAttributes($driver, $target);
# build caches for easier matching
foreach my $attribute (keys %{$attributes}) {
if (ref($$attributes{$attribute}) eq 'ARRAY') {
foreach my $value (@{$$attributes{$attribute}}) {
$toset{$attribute}->{$value} = FALSE;
}
} else {
$toset{$attribute}->{$$attributes{$attribute}} = FALSE;
}
}
foreach my $attribute (keys %{$_attributes}) {
next if ($$_attributes{$attribute}->{'static'});
if (defined($$_attributes{$attribute}->{'keys'})) {
foreach my $key (keys %{$$_attributes{$attribute}->{'keys'}}) {
my $value = $$_attributes{$attribute}->{'keys'}->{$key}->{'value'};
$existing{$attribute}->{$value} = FALSE
if (defined($value) && ($value ne ''));
}
} else {
my $value = $$_attributes{$attribute}->{'value'};
$existing{$attribute}->{$value} = FALSE
if (defined($value) && ($value ne ''));
}
}
# add/change
foreach my $attribute (keys %toset) {
foreach my $value (keys %{$toset{$attribute}}) {
if (!defined($existing{$attribute}) &&
$driverCap && !$SCST->checkTargetDynamicAttributes($driver, $attribute)) {
addTargetDynamicAttribute($driver, $target, $attribute, $value);
next;
}
# already set, move on
if (defined($existing{$attribute}->{$value})) {
$existing{$attribute}->{$value} = TRUE;
next;
}
# Set the existing attribute
if ($driverCap && !$SCST->checkTargetDynamicAttributes($driver, $attribute)) {
addTargetDynamicAttribute($driver, $target, $attribute, $value);
} else {
setTargetAttribute($target, $driver, $attribute, $value);
}
$existing{$attribute}->{$value} = TRUE;
}
}
foreach my $attribute (keys %existing) {
next if (!$driverCap || $SCST->checkTargetDynamicAttributes($driver, $attribute));
foreach my $value (keys %{$existing{$attribute}}) {
if (!$existing{$attribute}->{$value}) {
if ($deletions) {
removeTargetDynamicAttribute($driver, $target, $attribute, $value);
} else {
print "-> Target dynamic attribute '$attribute' with value '$value' ".
"is not in configuration. Use -force to remove it.\n";
}
}
}
}
}
sub addTargetDynamicAttribute {
my $driver = shift;
my $target = shift;
my $attribute = shift;
my $value = shift;
print "-> Attempting to add driver attribute '$attribute' with value '$value' ".
"for driver/target '$driver/$target': ";
my $rc = $SCST->addTargetDynamicAttribute($driver, $target, $attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub removeTargetDynamicAttribute {
my $driver = shift;
my $target = shift;
my $attribute = shift;
my $value = shift;
return if (!$SCST->driverIsVirtualCapable($driver));
print "-> Removing dynamic attribute '$attribute' with value '$value' for driver/target '$driver/$target': ";
my $rc = $SCST->removeTargetDynamicAttribute($driver, $target, $attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub setGroupAttributes {
my $target = shift;
my $driver = shift;
my $group = shift;
my $attributes = shift;
my $_attributes = $SCST->groupAttributes($driver, $target, $group);
foreach my $attribute (sort keys %{$attributes}) {
if (defined($$_attributes{$attribute}) &&
!$$_attributes{$attribute}->{'static'}) {
my $value = $$attributes{$attribute};
next if ($$_attributes{$attribute}->{'value'} eq $value);
print "-> Setting group attribute '$attribute' to value '$value' for ".
"driver/target/group '$driver/$target/$group': ";
my $rc = $SCST->setGroupAttribute($driver, $target, $group, $attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
} else {
print "-> WARNING: Driver/target/group '$driver/$target/$group' lacks the settable ".
"attribute '$attribute', ignoring.\n\n";
}
}
}
sub setLunAttributes {
my $lun = shift;
my $driver = shift;
my $target = shift;
my $attributes = shift;
my $group = shift;
my $_attributes = $SCST->lunAttributes($driver, $target, $lun, $group);
foreach my $attribute (sort keys %{$attributes}) {
if (defined($$_attributes{$attribute}) &&
!$$_attributes{$attribute}->{'static'}) {
my $value = $$attributes{$attribute};
next if ($$_attributes{$attribute}->{'value'} eq $value);
print "-> Setting LUN attribute '$attribute' to value '$value' for ".
"driver/target/group/lun '$driver/$target/$group/$lun': ";
my $rc = $SCST->setLunAttribute($driver, $target, $lun, $attribute, $value, $group);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
} else {
print "-> WARNING: Driver/target/group/lun '$driver/$target/$group/$lun' lacks the settable ".
"attribute '$attribute', ignoring.\n\n";
}
}
}
sub setInitiatorAttributes {
my $initiator = shift;
my $driver = shift;
my $target = shift;
my $group = shift;
my $attributes = shift;
my $_attributes = $SCST->initiatorAttributes($driver, $target, $group, $initiator);
foreach my $attribute (sort keys %{$attributes}) {
if (defined($$_attributes{$attribute}) &&
!$$_attributes{$attribute}->{'static'}) {
my $value = $$attributes{$attribute};
next if ($$_attributes{$attribute}->{'value'} eq $value);
print "-> Setting initiator attribute '$attribute' to value '$value' for ".
"driver/target/group/initiator '$driver/$target/$group/$initiator': ";
my $rc = $SCST->setInitiatorAttribute($driver, $target, $group, $initiator,
$attribute, $value);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
} else {
print "-> WARNING: Driver/target/group/initiator '$driver/$target/$group/$initiator' ".
"lacks the settable attribute '$attribute', ignoring.\n\n";
}
}
}
####################################################################
sub openDevice {
my $device = shift;
my $handler = shift;
my $attributes = shift;
print "-> Opening device '$device' using handler '$handler': ";
my $rc = $SCST->openDevice($handler, $device, $attributes);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub closeDevice {
my $device = shift;
my $handler = shift;
my $force = shift;
my $attributes = $SCST->deviceAttributes($device);
return if (defined($$attributes{'scsi_device'}));
if (!$force) {
if (keys %{$$attributes{'exported'}}) {
listExported($device, $attributes);
immediateExit("Device '$device' still in use, aborting. ".
"Use -force to override.");
}
}
print "-> Closing device '$device' using handler '$handler': ";
my $rc = $SCST->closeDevice($handler, $device);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub resyncDevice {
my $device = shift;
my $rc = FALSE;
my %attributes = ('resync_size', 1);
setDeviceAttributes($device, \%attributes);
}
####################################################################
sub addGroup {
my $group = shift;
my $driver = shift;
my $target = shift;
print "-> Adding new group '$group' to driver/target '$driver/$target': ";
my $rc = $SCST->addGroup($driver, $target, $group);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub removeGroup {
my $group = shift;
my $driver = shift;
my $target = shift;
my $force = shift;
if (!$force) {
my $luns = $SCST->luns($driver, $target, $group);
my $initiators = $SCST->initiators($driver, $target, $group);
if ((keys %{$luns}) || ($#{$initiators} > -1)) {
listGroup($driver, $target, $group, $luns, $initiators);
immediateExit("Group is still in use, aborting. Use -force to override.");
}
}
print "-> Removing group '$group' from driver/target '$driver/$target': ";
my $rc = $SCST->removeGroup($driver, $target, $group);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
####################################################################
sub addInitiator {
my $initiator = shift;
my $driver = shift;
my $target = shift;
my $group = shift;
print "-> Adding new initiator '$initiator' to driver/target/group ".
"'$driver/$target/$group': ";
my $rc = $SCST->addInitiator($driver, $target, $group, $initiator);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub removeInitiator {
my $initiator = shift;
my $driver = shift;
my $target = shift;
my $group = shift;
print "-> Removing initiator '$initiator' from driver/target/group ".
"'$driver/$target/$group': ";
my $rc = $SCST->removeInitiator($driver, $target, $group, $initiator);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub moveInitiator {
my $initiator = shift;
my $driver = shift;
my $target = shift;
my $group = shift;
my $to = shift;
print "-> Moving initiator '$initiator' from group '$group' to group '$to': ";
my $rc = $SCST->moveInitiator($driver, $target, $group, $to, $initiator);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub clearInitiators {
my $driver = shift;
my $target = shift;
my $group = shift;
print "-> Removing all initiators driver/target/group '$driver/$target/$group': ";
my $rc = $SCST->clearInitiators($driver, $target, $group);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
####################################################################
sub addLun {
my $lun = shift;
my $driver = shift;
my $target = shift;
my $device = shift;
my $attributes = shift;
my $group = shift;
if ($group) {
print "-> Adding device '$device' at LUN $lun to driver/target/group ".
"'$driver/$target/$group': ";
} else {
print "-> Adding device '$device' at LUN $lun to driver/target ".
"'$driver/$target': ";
}
my $rc = $SCST->addLun($driver, $target, $device, $lun, $attributes, $group);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub removeLun {
my $lun = shift;
my $driver = shift;
my $target = shift;
my $device = shift;
my $group = shift;
if ($group) {
print "-> Removing device '$device' at LUN $lun from driver/target/group ".
"'$driver/$target/$group': ";
} else {
print "-> Removing device '$device' at LUN $lun from driver/target ".
"'$driver/$target': ";
}
my $rc = $SCST->removeLun($driver, $target, $device, $lun, $group);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub replaceLun {
my $lun = shift;
my $driver = shift;
my $target = shift;
my $group = shift;
my $device = shift;
my $attributes = shift;
print "-> Replacing device '$device' at LUN $lun with device '$device' ".
"in driver/target/group '$driver/$target/$group': ";
my $rc = $SCST->replaceLun($driver, $target, $group, $lun, $device, $attributes);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub clearLuns {
my $driver = shift;
my $target = shift;
my $group = shift;
print "-> Removing all LUNs from driver/target/group '$driver/$target/$group': ";
my $rc = $SCST->clearLuns($driver, $target, $group);
print "done.\n";
immediateExit($SCST->errorString($rc)) if ($rc);
}
sub removeDriverDynamicAttributes {
my $driver = shift;
return if (!$SCST->driverIsVirtualCapable($driver));
print "-> Removing all dynamic attributes from driver '$driver': ";
my $attributes = $SCST->driverAttributes($driver);
my $dynamic = $SCST->driverDynamicAttributes($driver);
foreach my $attribute (keys %{$attributes}) {
if (defined($$dynamic{$attribute})) {
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (keys %{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
my $rc = $SCST->removeDriverDynamicAttribute($driver, $attribute, $value);
immediateExit($SCST->errorString($rc)) if ($rc);
}
}
}
}
print "done.\n";
}
sub removeTargetDynamicAttributes {
my $driver = shift;
my $target = shift;
return if (!$SCST->driverIsVirtualCapable($driver));
print "-> Removing all dynamic attributes from driver/target '$driver/$target': ";
my $attributes = $SCST->targetAttributes($driver, $target);
my $dynamic = $SCST->targetDynamicAttributes($driver);
foreach my $attribute (keys %{$attributes}) {
if (defined($$dynamic{$attribute})) {
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (keys %{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
my $rc = $SCST->removeTargetDynamicAttribute($driver, $target, $attribute, $value);
immediateExit($SCST->errorString($rc)) if ($rc);
}
}
}
}
print "done.\n";
}
####################################################################
sub enableTarget {
my $target = shift;
}
sub disableTarget {
my $target = shift;
}
sub issueLip {
}
####################################################################
sub readConfig {
my $file = shift;
my $buffer;
my @stanza;
my $level;
my $io = new IO::File $file, O_RDONLY;
immediateExit("Unable to open configuration file '$file': $!")
if (!$io);
while (my $line = <$io>) {
my($test, undef) = split(/\#/, $line, 2);
if ($test =~ /\[(.*)\s+.*\]/) {
my $parm = $1;
if (($parm eq 'HANDLER') || ($parm eq 'GROUP') ||
($parm eq 'ASSIGNMENT')) {
print "\nWARNING: Using a deprecated configuration file. ".
"I will attempt to convert it for you.\n\n";
return readOldConfig($file);
}
}
$buffer .= $line;
}
my @buff_a;
@buff_a = split(//, $buffer);
return parseStanza(\@buff_a);
}
sub parseStanza {
my $buffer = shift;
my $line;
my %hash;
my $attribute;
my $value;
my $value2;
my $quoted;
while ($#{$buffer} > -1) {
my $char = shift @{$buffer};
if ($char eq '{') {
my $child = parseStanza($buffer);
if ($line) {
parseLine($line, \%hash, $child);
$line = undef;
}
next;
}
return \%hash if ($char eq '}');
if ($char eq "\n") {
my %empty;
parseLine($line, \%hash, \%empty);
$line = undef;
} else {
$line .= $char;
}
}
return \%hash;
}
sub parseLine {
my $line = shift;
my $hash = shift;
my $child = shift;
($line, undef) = split(/\#/, $line, 2);
return if ($line =~ /^\s*$/);
$line =~ s/^\s+//; $line =~ s/\s+$//;
my @elements;
while ($line =~ m/"([^"\\]*(\\.[^"\\]*)*)"|([^\s]+)/g) {
push @elements, defined($1) ? $1:$3;
}
my $attribute = @elements[0];
my $value = @elements[1];
my $value2 = @elements[2];
if (defined($attribute) && defined($value) && defined($value2)) {
$$hash{$attribute}->{$value}->{$value2} = $child;
} elsif (defined($attribute) && defined($value)) {
$$hash{$attribute}->{$value} = $child;
} elsif (defined($attribute)) {
$$hash{$attribute} = $child;
}
}
sub readOldConfig {
my $confile = shift;
my $ignoreError = shift;
my %config;
my $section;
my $last_section;
my $arg;
my $last_arg;
my %empty;
my $io = new IO::File $confile, O_RDONLY;
if (!$io) {
return undef if ($ignoreError);
die("FATAL: Unable to open specified configuration file $confile: $!\n");
}
while (my $line = <$io>) {
($line, undef) = split(/\#/, $line, 2);
$line =~ s/^\s+//; $line =~ s/\s+$//;
if ($line =~ /^\[(.*)\]$/) {
($section, $arg) = split(/\s+/, $1, 2);
$arg = 'default' if ($section eq 'OPTIONS');
if ($last_arg && ($last_arg ne $arg) &&
!defined($config{$last_section}->{$last_arg})) {
$config{$last_section}->{$last_arg} = \%empty;
}
$last_arg = $arg;
$last_section = $section;
} elsif ($section && $arg && $line) {
my($attribute, $value) = split(/\s+/, $line, 2);
if ($section eq 'OPTIONS') {
$value = TRUE if (($value == 1) ||
($value =~ /^TRUE$/i) ||
($value =~ /^YES$/i));
$value = FALSE if (($value == 0) ||
($value =~ /^FALSE$/i) ||
($value =~ /^NO$/i));
}
push @{$config{$section}->{$arg}->{$attribute}}, $value;
}
}
close $io;
# Convert to our new format
my %new;
my %o_converts = ('WRITE_THROUGH' => 'write_through',
'WT' => 'write_through',
'READ_ONLY' => 'read_only',
'RO' => 'read_only',
'NV_CACHE' => 'nv_cache',
'NV' => 'nv_cache',
'REMOVABLE' => 'removable',
'RM' => 'removable');
foreach my $handler (keys %{$config{'HANDLER'}}) {
foreach my $device (@{$config{'HANDLER'}->{$handler}->{'DEVICE'}}) {
my($device, $path, $options, $bsize, $t10) = split(/\,/, $device);
my $_handler = $handler;
foreach my $option (split(/\|/, $options)) {
if (($option eq 'NULLIO') || ($option eq 'NIO')) {
$_handler = 'vdisk_nullio' if ($_handler eq 'vdisk');
} elsif (($option eq 'BLOCKIO') || ($option eq 'BIO')) {
$_handler = 'vdisk_blockio' if ($_handler eq 'vdisk');
}
}
if ($_handler eq 'vdisk') {
$_handler = 'vdisk_fileio';
}
foreach my $option (split(/\|/, $options)) {
if (defined($o_converts{$option})) {
%{$new{'HANDLER'}->{$_handler}->{'DEVICE'}->{$device}->{'CREATE_ATTRIBUTES'}->{$o_converts{$option}}->{'1'}} = ();
}
}
%{$new{'HANDLER'}->{$_handler}->{'DEVICE'}->{$device}->{'t10_dev_id'}->{$t10}} = ()
if ($t10);
%{$new{'HANDLER'}->{$_handler}->{'DEVICE'}->{$device}->{'CREATE_ATTRIBUTES'}->{'filename'}->{$path}} = ()
if ($path);
%{$new{'HANDLER'}->{$_handler}->{'DEVICE'}->{$device}->{'CREATE_ATTRIBUTES'}->{'blocksize'}->{$bsize}} = ()
if ($bsize);
}
}
foreach my $wwn (@{$config{'TARGETS'}->{'enable'}->{'HOST'}}) {
my $target = formatTarget($wwn);
my $driver = findTargetDriver($target);
if ($driver) {
%{$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'enabled'}->{'1'}} = ();
addAllGroupsToTarget(\%config, \%new, $driver, $target);
} else {
immediateExit("Unable to determine target driver information for target '$wwn'. ".
"Please ensure this target driver is loaded.");
}
}
if (!scalar keys %{$new{'TARGET_DRIVER'}}) {
print "WARNING: No targets set to 'enable' within your configuration file. Please be sure to ".
"save write your configuration with -write_config and review it carefully.\n\n";
# Fill in with known targets, all disabled.
my $drivers = $SCST->drivers();
foreach my $driver (@{$drivers}) {
my $targets = $SCST->targets($driver);
foreach my $target (@{$targets}) {
%{$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'enabled'}->{'0'}} = ();
addAllGroupsToTarget(\%config, \%new, $driver, $target);
}
}
}
# Now handle default groups
foreach my $group (keys %{$config{'ASSIGNMENT'}}) {
next if ($group !~ /^Default/);
my $drivers = $SCST->drivers();
if ($group eq 'Default') { # Add to all targets
foreach my $device (@{$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
my($device, $lun) = split(/\,/, $device);
foreach my $driver (@{$drivers}) {
my $targets = $SCST->targets($driver);
foreach my $target (@{$targets}) {
$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'enabled'}->{'0'} = ()
if (!defined($new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}));
$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'LUN'}->{$lun}->{$device} = {};
}
}
}
} else {
$group =~ s/^Default\_//;
my $found_t = FALSE;
# Find the associated target
foreach my $driver (@{$drivers}) {
my $targets = $SCST->targets($driver);
foreach my $target (@{$targets}) {
if ($target eq $group) {
foreach my $device (@{$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
my($device, $lun) = split(/\,/, $device);
$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'enabled'}->{'0'} = ()
if (!defined($new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}));
$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'LUN'}->{$lun}->{$device} = {};
}
$found_t = TRUE;
}
}
}
if (!$found_t) {
print "WARNING: Unable to find target $group. Please ".
"configure these assignments manually.\n\n";
}
}
}
return \%new;
}
sub addAllGroupsToTarget {
my $config = shift;
my $new = shift;
my $driver = shift;
my $target = shift;
foreach my $group (keys %{$$config{'GROUP'}}) {
%{$$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'GROUP'}->{$group}} = ();
if (defined($$config{'GROUP'}->{$group}->{'USER'})) {
foreach my $user (@{$$config{'GROUP'}->{$group}->{'USER'}}) {
%{$$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'GROUP'}->{$group}->{'INITIATOR'}->{$user}} = ();
}
}
}
foreach my $group (keys %{$$config{'ASSIGNMENT'}}) {
next if ($group =~ /^Default/);
foreach my $device (@{$$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
my($device, $lun) = split(/\,/, $device);
%{$$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'GROUP'}->{$group}->{'LUN'}->{$lun}->{$device}} = ();
}
}
}
sub findTargetDriver {
my $target = shift;
foreach my $driver (keys %{$CURRENT{'assign'}}) {
foreach my $_target (keys %{$CURRENT{'assign'}->{$driver}}) {
$_target =~ tr/A-Z/a-z/;
return $driver if ($_target eq $target);
}
}
return undef;
}
sub formatTarget {
my $target = shift;
if ($target =~ /^0x/) {
$target =~ s/^0x//;
my($o1, $o2, $o3, $o4, $o5, $o6, $o7, $o8) = unpack("A2A2A2A2A2A2A2A2", $target);
$target = "$o1:$o2:$o3:$o4:$o5:$o6:$o7:$o8";
}
$target =~ tr/A-Z/a-z/;
return $target;
}
####################################################################
sub handlerHasDevice {
my $handler = shift;
my $device = shift;
return FALSE if (!defined($CURRENT{'handler'}->{$handler}));
foreach my $_device (@{$CURRENT{'handler'}->{$handler}}) {
return TRUE if ($_device eq $device);
}
return FALSE;
}
sub groupHasInitiator {
my $initiators = shift;
my $initiator = shift;
foreach my $_initiator (@{$initiators}) {
return TRUE if ($_initiator eq $initiator);
}
return FALSE;
}
sub configToAttr {
my $config = shift;
my %attributes;
foreach my $attr (keys %{$config}) {
if ((keys %{$$config{$attr}}) > 1) {
foreach my $value (keys %{$$config{$attr}}) {
push @{$attributes{$attr}}, $value if (defined($value) &&
($value ne ''));
}
} else {
foreach my $value (keys %{$$config{$attr}}) {
if (keys %{$$config{$attr}->{$value}}) {
immediateExit("Invalid configuration encountered. ".
"Attribute '$attr' has an invalid value.");
}
$attributes{$attr} = $value;
}
}
}
return \%attributes;
}
sub numerically {
$a <=> $b;
}
####################################################################
# If we have an unread error from SCST, exit immediately
sub immediateExit {
my $error = shift;
return if (!$error);
print "\n\nFATAL: Received the following error:\n\n\t";
print "$error\n\n";
exit 1;
}
# Hey! Stop that!
sub commitSuicide {
print "\n\nAborting immediately.\n";
exit 1;
}