Files
scst/scstadmin/scstadmin.sysfs
T
Mark Buechler bd48c8f119 - Check for non-existent devices and warn/remove them from read config.
- Error out if a target doesn't exist to prevent removing potentially
  good running config.
- Be sure to remove luns and initiators before the group they're in.



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1820 d57e44dd-8a1f-0410-8b47-8ef2f437770f
2010-07-13 19:12:44 +00:00

3080 lines
82 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 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,...>
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}->{'LUNS'} = $luns if (defined($luns));
my $groups = $SCST->groups($driver, $target);
immediateExit($SCST->errorString());
foreach my $group (@{$groups}) {
$CURRENT{'assign'}->{$driver}->{$target}->{'GROUPS'}->{$group}->{'INITIATORS'} =
$SCST->initiators($driver, $target, $group);
immediateExit($SCST->errorString());
$CURRENT{'assign'}->{$driver}->{$target}->{'GROUPS'}->{$group}->{'LUNS'} =
$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 ''));
}
} else {
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}->{'LUNS'};
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}->{'GROUPS'};
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}->{'GROUPS'}->{$group}->{'LUNS'};
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}->{'GROUPS'}->{$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";
$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";
$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";
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";
$no_targets = TRUE;
}
if (!$no_targets) {
foreach my $target (keys %{$$CONFIG{'TARGET_DRIVER'}->{$driver}->{'TARGET'}}) {
if (!defined($CURRENT{'assign'}->{$driver}->{$target})) {
print "\t-> FATAL: Target '$target' for driver '$driver' ".
"does not exist.\n" if (!$SCST->driverIsVirtualCapable($driver));
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";
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";
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";
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 "\t-> 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}->{'LUNS'};
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 "\t-> 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}->{'GROUPS'}}) {
next if ($group eq 'LUNS');
my $luns = $$assignments{$driver}->{$target}->{'GROUPS'}->{$group}->{'LUNS'};
my $inits = $$assignments{$driver}->{$target}->{'GROUPS'}->{$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 "\t-> 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 "\t-> 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 "\t-> 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}->{'GROUPS'}->{$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}->{'GROUPS'}->{$group}->{'LUNS'};
} else {
$c_luns = $CURRENT{'assign'}->{$driver}->{$target}->{'LUNS'};
}
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}->{'GROUPS'}->{$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}->{'GROUPS'}}) {
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";
}
}
}
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";
}
}
}
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";
}
}
}
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";
}
}
}
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";
}
}
}
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";
}
}
}
####################################################################
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. ".
"Please note, groups will ONLY be configured for targets set as 'enable' ".
"within your old configuration file.\n\n".
"Please save your new configuration with -write_config and review.\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'}} = ();
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'}}) {
foreach my $device (@{$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
my($device, $lun) = split(/\,/, $device);
%{$new{'TARGET_DRIVER'}->{$driver}->{'TARGET'}->{$target}->{'GROUP'}->{$group}->{'LUN'}->{$lun}->{$device}} = ();
}
}
} else {
immediateExit("Unable to determine target driver information for target '$wwn'. ".
"Please ensure this target driver is loaded.");
}
}
return \%new;
}
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;
}