mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-19 19:51:27 +00:00
- SCST.pm: Added resyncDevice() - SCST.pm: General cleanup. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@784 d57e44dd-8a1f-0410-8b47-8ef2f437770f
1586 lines
39 KiB
Perl
Executable File
1586 lines
39 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
$Version = 'SCST Configurator v1.0.6';
|
|
|
|
# Configures SCST
|
|
#
|
|
# Author: Mark R. Buechler
|
|
# License: GPLv2
|
|
# Copyright (c) 2005-2009 Mark R. Buechler
|
|
|
|
sub usage
|
|
{
|
|
die <<"EndUsage";
|
|
$Version
|
|
|
|
Usage:
|
|
General Operations
|
|
-config <config> : Configure SCST given the specified configuration file.
|
|
-ClearConfig : Clear all SCST configuration.
|
|
-WriteConfig <file> : Writes the current configuration out to the specified file.
|
|
-checkConfig <file> : Checks the saved configuration in the specified file.
|
|
-sessions : List current initiator sessions.
|
|
|
|
Target Driver Operations
|
|
-enable <wwn|host> : Enable target mode for driver at specified WWN or host.
|
|
-disable <wwn|host> : Disable target mode for driver at specified WWN or host.
|
|
|
|
Device Operations
|
|
-adddev <device> : Adds a device to a handler.
|
|
-handler <handler>
|
|
-path <path>
|
|
-options <options>
|
|
-blocksize <bytes>
|
|
-resyncdev <device> : Resync the size of a device with the initiator(s).
|
|
-handler <handler>
|
|
-RemoveDev <device> : Remove a device from a handler.
|
|
-handler <handler>
|
|
|
|
User Operations
|
|
-adduser <user> : Adds a user to a security group.
|
|
-group <group>
|
|
-RemoveUser <user> : Delete a user from a security group.
|
|
-group <group>
|
|
-ClearUsers : Clear all users from a given security group.
|
|
-group <group>
|
|
|
|
Group Operations
|
|
-addgroup <group> : Add a given group to available security groups.
|
|
-RemoveGroup <group> : Remove a give group from available security groups.
|
|
|
|
Assignment Operations
|
|
-assigndev <device> : Assign a given device to a security group.
|
|
-group <group>
|
|
-lun <lun>
|
|
-ReleaseDev <device> : Remove a given device from a security group.
|
|
-group <group>
|
|
-ClearDevs : Clear all device assignments for a security group.
|
|
-group <group>
|
|
|
|
Options
|
|
-ForceConfig : Force all configuration changes, even deletions (DANGER!).
|
|
|
|
Debugging (limited support)
|
|
-debug : Debug mode - don\'t do anything destructive.
|
|
|
|
Available Handlers:
|
|
disk, vdisk, disk_perf, cdrom, vcdrom, changer, modisk, modisk_perf, tape, tape_perf
|
|
|
|
Available Options for create and open:
|
|
WRITE_THROUGH, READ_ONLY, O_DIRECT, NULLIO, NV_CACHE, BLOCK_IO, REMOVABLE
|
|
|
|
Examples:
|
|
Enable target mode for fibre card specifying its WWN
|
|
scstadmin -enable 50:06:0B:00:00:39:71:78
|
|
|
|
Disable target mode for SCSI host specifying host number
|
|
scstadmin -disable host4
|
|
|
|
Create a new security group:
|
|
scstadmin -addgroup HOST01
|
|
|
|
Create a device given an already existing disk file:
|
|
scstadmin -adddev DISK01 -handler vdisk -path /vdisks/disk01.dsk -options READ_ONLY,WRITE_THROUGH
|
|
|
|
Assign a device to a security group:
|
|
scstadmin -assigndev DISK01 -group HOST01 -lun 1
|
|
|
|
EndUsage
|
|
}
|
|
|
|
use SCST::SCST;
|
|
use Getopt::Long;
|
|
use IO::File;
|
|
use IO::Dir;
|
|
use POSIX;
|
|
use strict;
|
|
|
|
my $_DEF_CONFIG_ = '/etc/scst.conf';
|
|
|
|
my $TRUE = 1;
|
|
my $FALSE = 0;
|
|
|
|
my $_MAX_LUNS_ = 255;
|
|
my $_DEFAULT_GROUP_ = 'Default';
|
|
|
|
my $_SCSI_CLASS_ = '/sys/class/scsi_host';
|
|
my $_FC_CLASS_ = '/sys/class/fc_host';
|
|
my $_SCSI_ISP_ = '/proc/scsi/isp';
|
|
my $_SCSITGT_QLAISP_ = '/proc/scsi_tgt/qla_isp';
|
|
|
|
my $SCST;
|
|
my $DEVICES;
|
|
my $TARGETS;
|
|
my %USERS;
|
|
my %ASSIGNMENTS;
|
|
my %HANDLERS;
|
|
my %GROUPS;
|
|
my $_DEBUG_;
|
|
|
|
my %_HANDLER_MAP_ = ('cdrom' => $SCST::SCST::CDROM_TYPE,
|
|
'changer' => $SCST::SCST::CHANGER_TYPE,
|
|
'disk' => $SCST::SCST::DISK_TYPE,
|
|
'vdisk' => $SCST::SCST::VDISK_TYPE,
|
|
'vcdrom' => $SCST::SCST::VCDROM_TYPE,
|
|
'disk_perf' => $SCST::SCST::DISKPERF_TYPE,
|
|
'modisk' => $SCST::SCST::MODISK_TYPE,
|
|
'modisk_perf' => $SCST::SCST::MODISKPERF_TYPE,
|
|
'tape' => $SCST::SCST::TAPE_TYPE,
|
|
'tape_perf' => $SCST::SCST::TAPEPERF_TYPE,
|
|
'processor' => $SCST::SCST::PROCESSOR_TYPE,
|
|
# Add in the dev_ names as well
|
|
'dev_cdrom' => $SCST::SCST::CDROM_TYPE,
|
|
'dev_changer' => $SCST::SCST::CHANGER_TYPE,
|
|
'dev_disk' => $SCST::SCST::DISK_TYPE,
|
|
'dev_disk_perf' => $SCST::SCST::DISKPERF_TYPE,
|
|
'dev_modisk' => $SCST::SCST::MODISK_TYPE,
|
|
'dev_modisk_perf' => $SCST::SCST::MODISKPERF_TYPE,
|
|
'dev_tape' => $SCST::SCST::TAPE_TYPE,
|
|
'dev_tape_perf' => $SCST::SCST::TAPEPERF_TYPE,
|
|
'dev_processor' => $SCST::SCST::PROCESSOR_TYPE);
|
|
|
|
my %_REVERSE_MAP_ = ($SCST::SCST::CDROM_TYPE => 'cdrom',
|
|
$SCST::SCST::CHANGER_TYPE => 'changer',
|
|
$SCST::SCST::DISK_TYPE => 'disk',
|
|
$SCST::SCST::VDISK_TYPE => 'vdisk',
|
|
$SCST::SCST::VCDROM_TYPE => 'vcdrom',
|
|
$SCST::SCST::DISKPERF_TYPE => 'disk_perf',
|
|
$SCST::SCST::MODISK_TYPE => 'modisk',
|
|
$SCST::SCST::MODISKPERF_TYPE => 'modisk_perf',
|
|
$SCST::SCST::TAPE_TYPE => 'tape',
|
|
$SCST::SCST::TAPEPERF_TYPE => 'tape_perf',
|
|
$SCST::SCST::PROCESSOR_TYPE => 'processor');
|
|
|
|
my %_HANDLER_TYPE_MAP_ = ($SCST::SCST::IOTYPE_PHYSICAL => 'physical',
|
|
$SCST::SCST::IOTYPE_VIRTUAL => 'virtual',
|
|
$SCST::SCST::IOTYPE_PERFORMANCE => 'performance');
|
|
|
|
$SIG{INT} = \&commitSuicide;
|
|
|
|
use vars qw($Version);
|
|
|
|
POSIX::setsid();
|
|
|
|
&main();
|
|
|
|
sub getArgs {
|
|
my $applyConfig;
|
|
my $forceConfig;
|
|
my $clearConfig;
|
|
my $writeConfig;
|
|
my $checkConfig;
|
|
my $showSessions;
|
|
my $addDev;
|
|
my $devPath;
|
|
my $resyncDev;
|
|
my $removeDev;
|
|
my $addUser;
|
|
my $removeUser;
|
|
my $clearUsers;
|
|
my $addGroup;
|
|
my $removeGroup;
|
|
my $assignDev;
|
|
my $releaseDev;
|
|
my $clearDevs;
|
|
my $devLun;
|
|
my $handler;
|
|
my $group;
|
|
my $options;
|
|
my $blocksize;
|
|
my $enable;
|
|
my $disable;
|
|
|
|
my $p = new Getopt::Long::Parser;
|
|
|
|
if (!$p->getoptions('config:s' => \$applyConfig,
|
|
'ClearConfig' => \$clearConfig,
|
|
'ForceConfig' => \$forceConfig,
|
|
'WriteConfig=s' => \$writeConfig,
|
|
'checkConfig=s' => \$checkConfig,
|
|
'sessions' => \$showSessions,
|
|
'adddev=s' => \$addDev,
|
|
'path=s' => \$devPath,
|
|
'RemoveDev=s' => \$removeDev,
|
|
'lun=s' => \$devLun,
|
|
'adduser=s' => \$addUser,
|
|
'RemoveUser=s' => \$removeUser,
|
|
'ClearUsers' => \$clearUsers,
|
|
'addgroup=s' => \$addGroup,
|
|
'RemoveGroup=s' => \$removeGroup,
|
|
'assigndev=s' => \$assignDev,
|
|
'resyncdev=s' => \$resyncDev,
|
|
'ReleaseDev=s' => \$releaseDev,
|
|
'ClearDevs' => \$clearDevs,
|
|
'handler=s' => \$handler,
|
|
'group=s' => \$group,
|
|
'options=s' => \$options,
|
|
'blocksize=s' => \$blocksize,
|
|
'enable=s' => \$enable,
|
|
'disable=s' => \$disable,
|
|
'debug' => \$_DEBUG_)) {
|
|
&usage();
|
|
}
|
|
|
|
if ((defined($enable) && !$enable) || (defined($disable) && !$disable)) {
|
|
print "Argument -enable/-disable requires a WWN or host.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($handler && !$_HANDLER_MAP_{$handler}) {
|
|
print "Invalid handler '$handler' specified. Available handlers are:\n\n";
|
|
foreach my $_handler (keys %_HANDLER_MAP_) {
|
|
print "\t$_handler\n";
|
|
}
|
|
print "\n";
|
|
exit 1;
|
|
}
|
|
|
|
if ($addDev && !($handler && $devPath)) {
|
|
print "Please specify -handler and -path with -adddev.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if (defined($blocksize) && !$blocksize) {
|
|
print "Please specify bytes with -blocksize.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($blocksize && !$addDev) {
|
|
print "Please specify -adddev with -blocksize.\n";
|
|
usage();
|
|
}
|
|
|
|
if (defined($forceConfig) && !defined($applyConfig)) {
|
|
print "Please specify -config with -ForceConfig.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($resyncDev && !$handler) {
|
|
print "Please specify -handler with -resyncdev.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($removeDev && !$handler) {
|
|
print "Please specify -handler with -RemoveDev.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($addUser && !defined($group)) {
|
|
print "Please specify -group with -adduser.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($removeUser && !defined($group)) {
|
|
print "Please specify -group with -RemoveUser.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($clearUsers && !defined($group)) {
|
|
print "Please specify -group with -ClearUsers.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($assignDev && !(defined($group) && defined($devLun))) {
|
|
print "Please specify -group and -lun with -assigndev.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($releaseDev && !defined($group)) {
|
|
print "Please specify -group with -ReleaseDev.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if ($clearDevs && !defined($group)) {
|
|
print "Please specify -group with -ClearDevs.\n\n";
|
|
usage();
|
|
}
|
|
|
|
if (defined($writeConfig) && !$writeConfig) {
|
|
print "Please specify a file name to write configuration to..\n\n";
|
|
usage();
|
|
}
|
|
|
|
$_DEBUG_ = $TRUE if (defined($_DEBUG_));
|
|
|
|
$forceConfig = $TRUE if (defined($forceConfig));
|
|
$showSessions = $TRUE if (defined($showSessions));
|
|
|
|
$enable =~ tr/A-Z/a-z/; $disable =~ tr/A-Z/a-z/;
|
|
$options =~ tr/a-z/A-Z/ if ($options);
|
|
|
|
if ((defined($showSessions) + defined($addDev) + defined($resyncDev) +
|
|
defined($removeDev)+ defined($addUser) + defined($enable) + defined($disable) +
|
|
defined($removeUser) + defined($clearUsers) + defined($assignDev) +
|
|
defined($releaseDev) + defined($clearDevs) + defined($applyConfig) +
|
|
defined($clearConfig) + defined($writeConfig) + defined($checkConfig)) > 1) {
|
|
print "Please specify only one operation at a time.\n";
|
|
usage();
|
|
}
|
|
|
|
$applyConfig = $_DEF_CONFIG_ if (defined($applyConfig) && !$applyConfig);
|
|
$checkConfig = $_DEF_CONFIG_ if (defined($checkConfig) && !$checkConfig);
|
|
|
|
return ($enable, $disable, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser,
|
|
$removeUser, $clearUsers, $addGroup, $removeGroup, $assignDev, $releaseDev,
|
|
$clearDevs, $handler, $group, $options, $blocksize, $applyConfig, $forceConfig,
|
|
$clearConfig, $writeConfig, $checkConfig, $showSessions);
|
|
}
|
|
|
|
sub main {
|
|
my $rc;
|
|
|
|
STDOUT->autoflush(1);
|
|
|
|
# We need to run as root
|
|
if ( $> ) {die("This program must run as root.\n");}
|
|
|
|
my ($enable, $disable, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser,
|
|
$removeUser, $clearUsers, $addGroup, $removeGroup, $assignDev, $releaseDev,
|
|
$clearDevs, $handler, $group, $options, $blocksize, $applyConfig, $forceConfig,
|
|
$clearConfig, $writeConfig, $checkConfig, $showSessions) = getArgs();
|
|
|
|
$SCST = new SCST::SCST($_DEBUG_);
|
|
|
|
readWorkingConfig();
|
|
|
|
SWITCH: {
|
|
$applyConfig && do {
|
|
if ($forceConfig) {
|
|
$rc = applyConfiguration($applyConfig, $FALSE, $TRUE);
|
|
die("Configuration errors found, aborting.\n") if ($rc);
|
|
|
|
print "\nConfiguration will apply in 10 seconds, type ctrl-c to abort..\n";
|
|
sleep 10;
|
|
}
|
|
|
|
readWorkingConfig();
|
|
$rc = applyConfiguration($applyConfig, $forceConfig, $FALSE);
|
|
last SWITCH;
|
|
};
|
|
$checkConfig && do {
|
|
$rc = applyConfiguration($checkConfig, $FALSE, $TRUE);
|
|
last SWITCH;
|
|
};
|
|
$writeConfig && do {
|
|
$rc = writeConfiguration($writeConfig);
|
|
last SWITCH;
|
|
};
|
|
$showSessions && do {
|
|
$rc = showSessions();
|
|
last SWITCH;
|
|
};
|
|
defined($clearConfig) && do {
|
|
$rc = clearConfiguration();
|
|
last SWITCH;
|
|
};
|
|
$addDev && do {
|
|
$rc = addDevice($handler, $addDev, $devPath, $options, $blocksize);
|
|
last SWITCH;
|
|
};
|
|
$resyncDev && do {
|
|
$rc = resyncDevice($handler, $resyncDev);
|
|
last SWITCH;
|
|
};
|
|
$removeDev && do {
|
|
$rc = removeDevice($handler, $removeDev);
|
|
last SWITCH;
|
|
};
|
|
$addUser && do {
|
|
$rc = addUser($group, $addUser);
|
|
last SWITCH;
|
|
};
|
|
$removeUser && do {
|
|
$rc = removeUser($group, $removeUser);
|
|
last SWITCH;
|
|
};
|
|
defined($clearUsers) && do {
|
|
$rc = clearUsers($group);
|
|
last SWITCH;
|
|
};
|
|
$addGroup && do {
|
|
$rc = addGroup($addGroup);
|
|
last SWITCH;
|
|
};
|
|
$removeGroup && do {
|
|
$rc = removeGroup($removeGroup);
|
|
last SWITCH;
|
|
};
|
|
$assignDev && do {
|
|
$rc = assignDevice($group, $assignDev, $devLun);
|
|
last SWITCH;
|
|
};
|
|
$releaseDev && do {
|
|
$rc = releaseDevice($group, $releaseDev);
|
|
last SWITCH;
|
|
};
|
|
defined($clearDevs) && do {
|
|
$rc = clearDevices($group);
|
|
last SWITCH;
|
|
};
|
|
$enable && do {
|
|
$enable = unformatTarget($enable);
|
|
$rc = enableTarget($enable, $TRUE);
|
|
last SWITCH;
|
|
};
|
|
$disable && do {
|
|
$disable = unformatTarget($disable);
|
|
$rc = enableTarget($disable, $FALSE);
|
|
last SWITCH;
|
|
};
|
|
|
|
print "No valid operations specified.\n";
|
|
usage();
|
|
exit $TRUE;
|
|
}
|
|
|
|
print "All done.\n";
|
|
|
|
exit $rc;
|
|
}
|
|
|
|
sub readWorkingConfig {
|
|
my %empty;
|
|
|
|
print "Collecting current configuration.. ";
|
|
|
|
$TARGETS = undef;
|
|
$DEVICES = undef;
|
|
%HANDLERS = ();
|
|
%GROUPS = ();
|
|
%USERS = ();
|
|
|
|
my $eHandlers = $SCST->handlers();
|
|
|
|
immediateExit($SCST->errorString());
|
|
|
|
foreach my $handler (@{$eHandlers}) {
|
|
$HANDLERS{$handler}++; # For quick lookups
|
|
}
|
|
|
|
$TARGETS = targets();
|
|
|
|
$DEVICES = $SCST->devices();
|
|
immediateExit($SCST->errorString());
|
|
|
|
my $_eGroups = $SCST->groups();
|
|
immediateExit($SCST->errorString());
|
|
|
|
foreach my $group (@{$_eGroups}) {
|
|
$GROUPS{$group}++;
|
|
$ASSIGNMENTS{$group} = $SCST->groupDevices($group);
|
|
my $eUsers = $SCST->users($group);
|
|
|
|
foreach my $user (@{$eUsers}) {
|
|
$USERS{$group}->{$user}++; # For quick lookups
|
|
}
|
|
$USERS{$group} = \%empty if (!$USERS{$group});
|
|
}
|
|
|
|
print "done.\n\n";
|
|
}
|
|
|
|
sub writeConfiguration {
|
|
my $file = shift;
|
|
|
|
if (-f $file) {
|
|
if (!unlink $file) {
|
|
print "Failed to save current configuration, specified ".
|
|
"file exists and cannot be deleted.\n";
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
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";
|
|
|
|
# Device information
|
|
foreach my $handler (sort keys %HANDLERS) {
|
|
print $io "[HANDLER ".$_REVERSE_MAP_{$handler}."]\n";
|
|
|
|
if ($SCST->handlerType($handler) == $SCST::SCST::IOTYPE_VIRTUAL) {
|
|
print $io "#DEVICE <vdisk name>,<device path>";
|
|
if ($handler == $SCST::SCST::VDISK_TYPE) {
|
|
print $io ",<options>,<block size>\n";
|
|
} else {
|
|
print $io "\n";
|
|
}
|
|
} else {
|
|
print $io "#DEVICE <H:C:I:L>\n";
|
|
}
|
|
|
|
my $devices = $SCST->handlerDevices($handler);
|
|
|
|
immediateExit($SCST->errorString());
|
|
|
|
foreach my $device (sort keys %{$devices}) {
|
|
my $options = $$devices{$device}->{'OPTIONS'};
|
|
|
|
$options =~ s/\,/\|/g;
|
|
|
|
print $io "DEVICE $device,".$$devices{$device}->{'PATH'};
|
|
print $io ",$options";
|
|
print $io ",".$$devices{$device}->{'BLOCKSIZE'};
|
|
print $io "\n";
|
|
}
|
|
|
|
print $io "\n";
|
|
}
|
|
|
|
# User configuration
|
|
foreach my $group (sort keys %USERS) {
|
|
print $io "[GROUP $group]\n";
|
|
print $io "#USER <user wwn>\n";
|
|
|
|
foreach my $user (keys %{$USERS{$group}}) {
|
|
print $io "USER $user\n";
|
|
}
|
|
|
|
print $io "\n";
|
|
}
|
|
|
|
# Assignments configuration
|
|
foreach my $group (sort keys %ASSIGNMENTS) {
|
|
print $io "[ASSIGNMENT $group]\n";
|
|
print $io "#DEVICE <device name>,<lun>\n";
|
|
|
|
my $pointer = $ASSIGNMENTS{$group};
|
|
foreach my $device (sort keys %{$pointer}) {
|
|
print $io "DEVICE $device,".$$pointer{$device}."\n";
|
|
}
|
|
|
|
print $io "\n";
|
|
}
|
|
|
|
# Targets configuration
|
|
foreach my $type ('enable', 'disable') {
|
|
print $io "[TARGETS $type]\n";
|
|
print $io "#HOST <wwn identifier>\n";
|
|
|
|
foreach my $target (sort keys %{$TARGETS}) {
|
|
if ((($type eq 'enable') && $$TARGETS{$target}->{'enabled'}) ||
|
|
(($type eq 'disable') && !$$TARGETS{$target}->{'enabled'})) {
|
|
my $f_target = formatTarget($target);
|
|
print $io "HOST $f_target\n" if (!$$TARGETS{$target}->{'duplicate'});
|
|
}
|
|
}
|
|
|
|
print $io "\n";
|
|
}
|
|
|
|
print "done\n";
|
|
|
|
close $io;
|
|
|
|
return 0;
|
|
}
|
|
|
|
sub applyConfiguration {
|
|
my $confile = shift;
|
|
my $force = shift;
|
|
my $check = shift;
|
|
my $config = readConfig($confile);
|
|
my $errs;
|
|
my $changes = 0;
|
|
|
|
my %used_devs;
|
|
my %used_users;
|
|
my %used_assignments;
|
|
my %empty;
|
|
|
|
# Cache device/handler configuration
|
|
foreach my $entry (keys %{$$config{'HANDLER'}}) {
|
|
foreach my $device (@{$$config{'HANDLER'}->{$entry}->{'DEVICE'}}) {
|
|
my($vname, undef) = split(/\,/, $device, 2);
|
|
$vname = cleanupString($vname);
|
|
$used_devs{$vname} = $entry;
|
|
}
|
|
}
|
|
|
|
# Cache user/group configuration
|
|
foreach my $group (keys %{$$config{'GROUP'}}) {
|
|
foreach my $user (@{$$config{'GROUP'}->{$group}->{'USER'}}) {
|
|
$used_users{$group}->{$user}++;
|
|
}
|
|
$used_users{$group} = \%empty if (!$used_users{$group});
|
|
}
|
|
|
|
# Cache device association configuration
|
|
foreach my $group (keys %{$$config{'ASSIGNMENT'}}) {
|
|
foreach my $device (@{$$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
|
|
my($vname, $lun) = split(/\,/, $device);
|
|
$vname = cleanupString($vname);
|
|
$used_assignments{$group}->{$vname} = $lun;
|
|
}
|
|
}
|
|
|
|
# If -ForceConfig is used, check for configurations which we've deleted but are still active.
|
|
if ($force || $check) {
|
|
# Associations
|
|
foreach my $group (sort keys %ASSIGNMENTS) {
|
|
if (!defined($used_assignments{$group}) && (keys %{$ASSIGNMENTS{$group}})) {
|
|
print "\t-> WARNING: Group '$group' has no associations in saved configuration";
|
|
|
|
if (!$check) {
|
|
print ", clearing all associations.\n";
|
|
if (clearDevices($group)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
} else {
|
|
print ".\n";
|
|
$changes++;
|
|
}
|
|
} else {
|
|
my $_assignments = $ASSIGNMENTS{$group};
|
|
|
|
foreach my $device (sort keys %{$_assignments}) {
|
|
if (!defined($used_assignments{$group}->{$device}) ||
|
|
($$_assignments{$device} != $used_assignments{$group}->{$device})) {
|
|
if ($$_assignments{$device} != $used_assignments{$group}->{$device}) {
|
|
print "\t-> WARNING: Device '$device' assigned to group '$group' is at LUN ".
|
|
$used_assignments{$group}->{$device}.
|
|
" whereas working configuration reflects LUN ".$$_assignments{$device};
|
|
} else {
|
|
print "\t-> WARNING: Device '$device' is not associated with group ".
|
|
"'$group' in saved configuration";
|
|
}
|
|
|
|
if (!$check) {
|
|
print ", releasing.\n";
|
|
if (releaseDevice($group, $device)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
} else {
|
|
print ".\n";
|
|
$changes++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Users & Groups
|
|
foreach my $group (sort keys %USERS) {
|
|
next if ($group eq $_DEFAULT_GROUP_);
|
|
if (!defined($used_users{$group})) {
|
|
print "\t-> WARNING: Group '$group' does not exist in saved configuration";
|
|
|
|
if (!$check) {
|
|
print ", removing.\n";
|
|
if (clearUsers($group)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
|
|
if (removeGroup($group)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
} else {
|
|
print ".\n";
|
|
$changes++;
|
|
}
|
|
} else {
|
|
foreach my $user (sort keys %{$USERS{$group}}) {
|
|
if (!defined($used_users{$group}->{$user})) {
|
|
print "\t-> WARNING: User '$user' is not defined as part of group '$group' ".
|
|
"in saved configuration";
|
|
|
|
if (!$check) {
|
|
print ", removing.\n";
|
|
if (removeUser($group, $user)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
} else {
|
|
print ".\n";
|
|
$changes++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Devices
|
|
foreach my $device (sort keys %{$DEVICES}) {
|
|
if ($$DEVICES{$device} && !defined($used_devs{$device})) {
|
|
# Device gone, but is it still assigned to a group?
|
|
my $isAssigned = $FALSE;
|
|
foreach my $group (sort keys %used_assignments) {
|
|
if (defined($used_assignments{$group}->{$device})) {
|
|
print "\t-> WARNING: Device '$device' is not defined in saved configuration, ".
|
|
"however, it is still assigned to group '$group'! Ignoring removal.\n";
|
|
$isAssigned = $TRUE;
|
|
}
|
|
}
|
|
|
|
if (!$isAssigned && ($SCST->handlerType($$DEVICES{$device}) == $SCST::SCST::IOTYPE_VIRTUAL)) {
|
|
print "\t-> WARNING: Device '$device' is not defined in saved configuration";
|
|
|
|
if (!$check) {
|
|
print ", removing.\n";
|
|
if (removeDevice($_REVERSE_MAP_{$$DEVICES{$device}}, $device)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
} else {
|
|
print ".\n";
|
|
$changes++;
|
|
}
|
|
}
|
|
} else {
|
|
# Handler change
|
|
if ($_HANDLER_MAP_{$used_devs{$device}} != $$DEVICES{$device}) {
|
|
my $handler = $used_devs{$device};
|
|
|
|
if ($HANDLERS{$_HANDLER_MAP_{$handler}}) {
|
|
print "\t-> WARNING: Device '$device' changes handler to '$handler'";
|
|
|
|
if (!$check) {
|
|
print ", changing.\n";
|
|
if ($SCST->assignDeviceToHandler($device,
|
|
$_HANDLER_MAP_{$handler})) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
} else {
|
|
print ".\n";
|
|
$changes++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
print "Applying configuration additions..\n" if (!$check);
|
|
print "\n";
|
|
|
|
readWorkingConfig() if ($force);
|
|
|
|
foreach my $_handler (sort keys %{$$config{'HANDLER'}}) {
|
|
if (!$HANDLERS{$_HANDLER_MAP_{$_handler}}) {
|
|
print "\t-> WARNING: Handler '$_handler' does not exist.\n";
|
|
$errs += 1;
|
|
next;
|
|
}
|
|
|
|
foreach my $device (@{$$config{'HANDLER'}->{$_handler}->{'DEVICE'}}) {
|
|
my($vname, $path, $options, $blocksize) = split(/\,/, $device);
|
|
$path = cleanupString($path);
|
|
$options =~ s/\s+//g;
|
|
|
|
if (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} == $$DEVICES{$vname})) {
|
|
next;
|
|
} elsif (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} != $$DEVICES{$vname})) {
|
|
if ($HANDLERS{$_HANDLER_MAP_{$_handler}}) {
|
|
print "\t-> WARNING: Device '$vname' changes handler from '".
|
|
$_REVERSE_MAP_{$$DEVICES{$vname}}."' to '$_handler'.\n".
|
|
"\t Use -ForceConfig to change device handler.\n" if (!$force && !$check);
|
|
}
|
|
next;
|
|
}
|
|
|
|
if ($check) {
|
|
print "\t-> New device '$_handler:$vname' at path '$path', options '$options', ".
|
|
"blocksize $blocksize.\n";
|
|
$$DEVICES{$vname} = $_HANDLER_MAP_{$_handler};
|
|
$changes++;
|
|
} else {
|
|
if (addDevice($_handler, $vname, $path, $options, $blocksize)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create new groups and add users..
|
|
foreach my $group (keys %used_users) {
|
|
if (!defined($USERS{$group})) {
|
|
if ($check) {
|
|
print "\t-> New group definition '$group.'\n";
|
|
$GROUPS{$group}++;
|
|
$changes++;
|
|
} else {
|
|
if (addGroup($group)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach my $user (keys %{$used_users{$group}}) {
|
|
if (!defined($USERS{$group}->{$user})) {
|
|
if ($check) {
|
|
print "\t-> New user definition '$user' for group '$group'.\n";
|
|
$USERS{$group}->{$user}++;
|
|
$changes++;
|
|
} else {
|
|
if (addUser($group, $user)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Assign new devices to groups..
|
|
foreach my $group (keys %used_assignments) {
|
|
if (!defined($GROUPS{$group})) {
|
|
# Looks like we're lacking a group. We'll create an empty one
|
|
|
|
print "\t-> WARNING: Auto-creating an empty group '$group' since none was configured.\n";
|
|
|
|
if (addGroup($group)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
}
|
|
|
|
if (!defined($GROUPS{$group})) {
|
|
print "\t-> WARNING: Unable to assign to non-existant group '$group'.\n";
|
|
$errs += 1;
|
|
next;
|
|
}
|
|
|
|
foreach my $vname (keys %{$used_assignments{$group}}) {
|
|
my $lun = $used_assignments{$group}->{$vname};
|
|
my $_assignments = $ASSIGNMENTS{$group};
|
|
|
|
if (defined($$_assignments{$vname}) && ($$_assignments{$vname} == $lun)) {
|
|
next;
|
|
} elsif (defined($$_assignments{$vname}) && ($$_assignments{$vname} != $lun)) {
|
|
print "\t-> Device '$vname' assigned to group '$group' is at LUN ".$$_assignments{$vname}.
|
|
", whereas the working configuration reflects LUN $lun.\n".
|
|
"\t Use -ForceConfig to force this LUN change.\n" if (!$force && !$check);
|
|
} else {
|
|
if ($check) {
|
|
$lun = 'auto' if (!defined($lun));
|
|
print "\t-> New device assignment for '$vname' to group '$group' at LUN $lun.\n";
|
|
$changes++;
|
|
} else {
|
|
if (assignDevice($group, $vname, $lun)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Enable/Disable configured targets
|
|
foreach my $type (keys %{$$config{'TARGETS'}}) {
|
|
my $enable;
|
|
|
|
if ($type eq 'enable') {
|
|
$enable = $TRUE;
|
|
} elsif ($type eq 'disable') {
|
|
$enable = $FALSE;
|
|
} else {
|
|
print "\t-> WARNING: Ignoring invalid TARGETS specifier '$type'. ".
|
|
"Should be one of enable,disable.\n";
|
|
next;
|
|
}
|
|
|
|
foreach my $target (@{$$config{'TARGETS'}->{$type}->{'HOST'}}) {
|
|
my $i_target = unformatTarget($target);
|
|
|
|
if (!defined($$TARGETS{$i_target})) {
|
|
print "\t-> WARNING: Target '$target' not found on system.\n";
|
|
$errs += 1;
|
|
next;
|
|
}
|
|
|
|
next if ($enable == targetEnabled($i_target));
|
|
|
|
if (!$enable && targetEnabled($target)) {
|
|
if ($force || $check) {
|
|
print "\t-> WARNING: Target mode for '$target' is currently enabled, ".
|
|
"however configuration file wants it disabled";
|
|
|
|
if (!$check) {
|
|
print ", disabling.\n";
|
|
if (enableTarget($target, $enable)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
} else {
|
|
print ".\n";
|
|
$changes++;
|
|
}
|
|
}
|
|
} else {
|
|
print "\t-> Target '$target' is enabled in configuration file, ".
|
|
"however is currently disabled";
|
|
|
|
if (!$check) {
|
|
print ", enabling.\n";
|
|
if (enableTarget($target, $enable)) {
|
|
$errs++;
|
|
} else {
|
|
$changes++;
|
|
}
|
|
} else {
|
|
print ".\n";
|
|
$changes++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
print "\nEncountered $errs error(s) while processing.\n" if ($errs);
|
|
|
|
if ($check) {
|
|
print "Configuration checked, $changes difference(s) found with working configuration.\n";
|
|
} else {
|
|
$changes = 0 if ($_DEBUG_);
|
|
print "Configuration applied, $changes changes made.\n";
|
|
}
|
|
|
|
return $TRUE if ($errs);
|
|
return $FALSE;
|
|
}
|
|
|
|
sub clearConfiguration {
|
|
my $errs;
|
|
|
|
print "WARNING: This removes ALL applied SCST configuration and may result in data loss!\n";
|
|
print "If this is not what you intend, press ctrl-c now. Waiting 10 seconds.\n\n";
|
|
sleep 10;
|
|
|
|
print "\nRemoving all users and groups:\n\n";
|
|
foreach my $group (keys %GROUPS) {
|
|
$errs += removeGroup($group) if ($group ne $_DEFAULT_GROUP_);
|
|
}
|
|
|
|
print "\nRemoving all handler devices:\n\n";
|
|
foreach my $device (keys %{$DEVICES}) {
|
|
next if (!$$DEVICES{$device});
|
|
next if ($SCST->handlerType($$DEVICES{$device}) != $SCST::SCST::IOTYPE_VIRTUAL);
|
|
$errs += removeDevice($_REVERSE_MAP_{$$DEVICES{$device}}, $device);
|
|
}
|
|
|
|
print "\nEncountered $errs error(s) while processing.\n" if ($errs);
|
|
print "\nConfiguration cleared.\n";
|
|
|
|
return $TRUE if ($errs);
|
|
return $FALSE;
|
|
}
|
|
|
|
sub showSessions {
|
|
my $sessions = $SCST->sessions();
|
|
immediateExit($SCST->errorString());
|
|
|
|
print "\n\tTarget Name\tInitiator Name\t\t\tGroup Name\t\tCommand Count\n";
|
|
|
|
foreach my $target (keys %{$sessions}) {
|
|
foreach my $group (keys %{$$sessions{$target}}) {
|
|
foreach my $user (keys %{$$sessions{$target}->{$group}}) {
|
|
my $commands = $$sessions{$target}->{$group}->{$user};
|
|
|
|
print "\t$target\t$user\t\t$group\t\t$commands\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
print "\n";
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub addDevice {
|
|
my $handler = shift;
|
|
my $device = shift;
|
|
my $path = shift;
|
|
my $options = shift;
|
|
my $blocksize = shift;
|
|
|
|
my $_handler = $_HANDLER_MAP_{$handler};
|
|
my $htype = $SCST->handlerType($_handler);
|
|
|
|
if (!$htype) {
|
|
print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if ($htype != $SCST::SCST::IOTYPE_VIRTUAL) {
|
|
my $typeString = $_HANDLER_TYPE_MAP_{$htype};
|
|
my $validType = $_HANDLER_TYPE_MAP_{$SCST::SCST::IOTYPE_VIRTUAL};
|
|
print "WARNING: Handler $handler of type $typeString is incapable of ".
|
|
"opening/closing devices. Valid handlers are:\n".
|
|
validHandlerTypes($SCST::SCST::IOTYPE_VIRTUAL)."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if (defined($$DEVICES{$device})) {
|
|
print "WARNING: Device '$device' already defined.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Opening virtual device '$device' at path '$path' using handler '$handler'..\n";
|
|
|
|
if ($SCST->openDevice($_handler, $device, $path, $options, $blocksize)) {
|
|
print "WARNING: Failed to open virtual device '$device' at path '$path': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
$$DEVICES{$device} = $_handler;
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub resyncDevice {
|
|
my $handler = shift;
|
|
my $device = shift;
|
|
|
|
my $_handler = $_HANDLER_MAP_{$handler};
|
|
my $htype = $SCST->handlerType($_handler);
|
|
|
|
if (!defined($$DEVICES{$device})) {
|
|
print "WARNING: Device '$device' not defined.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Resync'ing virtual device '$device'..\n";
|
|
|
|
if ($SCST->resyncDevice($_handler, $device)) {
|
|
print "WARNING: Failed to resync virtual device '$device': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub removeDevice {
|
|
my $handler = shift;
|
|
my $device = shift;
|
|
|
|
my $_handler = $_HANDLER_MAP_{$handler};
|
|
my $htype = $SCST->handlerType($_handler);
|
|
|
|
if (!$htype) {
|
|
print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if ($htype != $SCST::SCST::IOTYPE_VIRTUAL) {
|
|
my $typeString = $_HANDLER_TYPE_MAP_{$htype};
|
|
my $validType = $_HANDLER_TYPE_MAP_{$SCST::SCST::IOTYPE_VIRTUAL};
|
|
print "WARNING: Handler $handler of type $typeString is incapable of ".
|
|
"opening/closing devices. Valid handlers are:\n".
|
|
validHandlerTypes($SCST::SCST::IOTYPE_VIRTUAL)."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if (!defined($$DEVICES{$device})) {
|
|
print "WARNING: Device '$device' not defined.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Closing virtual device '$device'..\n";
|
|
|
|
if ($SCST->closeDevice($_handler, $device)) {
|
|
print "WARNING: Failed to close virtual device '$device': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
undef $$DEVICES{$device};
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub addGroup {
|
|
my $group = shift;
|
|
|
|
if (defined($GROUPS{$group})) {
|
|
print "WARNING: Group '$group' already exists.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Creating security group '$group'..\n";
|
|
|
|
if ($SCST->addGroup($group)) {
|
|
print "WARNING: Failed to create security group '$group': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
$GROUPS{$group}++;
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub removeGroup {
|
|
my $group = shift;
|
|
|
|
return $FALSE if ($group eq $_DEFAULT_GROUP_);
|
|
|
|
if (!defined($GROUPS{$group})) {
|
|
print "WARNING: Group '$group' does not exist.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Removing security group '$group'..\n";
|
|
|
|
if ($SCST->removeGroup($group)) {
|
|
print "WARNING: Failed to remove security group '$group': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
undef $GROUPS{$group};
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub addUser {
|
|
my $group = shift;
|
|
my $user = shift;
|
|
|
|
if (!defined($GROUPS{$group})) {
|
|
print "WARNING: Failed to add user '$user' to group '$group', group does not exist.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if (defined($USERS{$group}->{$user})) {
|
|
print "WARNING: User '$user' already exists in security group '$group'.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Adding user '$user' to security group '$group'..\n";
|
|
|
|
if ($SCST->addUser($user, $group)) {
|
|
print "WARNING: Failed to add user '$user' to security group '$group': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
$USERS{$group}->{$user}++;
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub removeUser {
|
|
my $group = shift;
|
|
my $user = shift;
|
|
|
|
if (!defined($GROUPS{$group})) {
|
|
print "WARNING: Failed to remove user '$user' from group '$group', group does not exist.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if (!defined($USERS{$group}->{$user})) {
|
|
print "WARNING: User '$user' doesn\'t exist in security group '$group'.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Removing user '$user' from security group '$group'..\n";
|
|
|
|
if ($SCST->removeUser($user, $group)) {
|
|
print "WARNING: Failed to remove user '$user' to security group '$group': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
undef $USERS{$group}->{$user};
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub clearUsers {
|
|
my $group = shift;
|
|
|
|
if (!defined($GROUPS{$group})) {
|
|
print "WARNING: Failed to clear users from group '$group', group does not exist.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Clearing users from security group '$group'..\n";
|
|
|
|
if ($SCST->clearUsers($group)) {
|
|
print "WARNING: Failed to clear users from security group '$group': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
undef $USERS{$group};
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub assignDevice {
|
|
my $group = shift;
|
|
my $device = shift;
|
|
my $lun = shift;
|
|
my %allLuns;
|
|
|
|
# Put luns into something easier to parse..
|
|
foreach my $_group (keys %ASSIGNMENTS) {
|
|
my $_gAssigns = $ASSIGNMENTS{$_group};
|
|
|
|
foreach my $_device (keys %{$_gAssigns}) {
|
|
@{$allLuns{$_group}}[$$_gAssigns{$_device}] = $_device;
|
|
}
|
|
}
|
|
|
|
# Use the next available LUN if none specified
|
|
if ($lun !~ /\d+/) {
|
|
$lun = ($#{$allLuns{$group}} + 1);
|
|
if ($lun > $_MAX_LUNS_) {
|
|
print "ERROR: Unable to use next available LUN of $lun, lun out of range.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Device '$device': Using next available LUN of $lun for group '$group'.\n";
|
|
}
|
|
|
|
if (($lun < 0) || ($lun > $_MAX_LUNS_)) {
|
|
print "ERROR: Unable to assign device '$device', lun '$lun' is out of range.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if (!defined($$DEVICES{$device})) {
|
|
print "WARNING: Unable to assign non-existant device '$device' to group '$group'.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if (@{$allLuns{$group}}[$lun]) {
|
|
print "ERROR: Device '$device': Lun '$lun' is already assigned to device '".@{$allLuns{$group}}[$lun]."'.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Assign virtual device '$device' to group '$group' at LUN '$lun'..\n";
|
|
|
|
if ($SCST->assignDeviceToGroup($device, $group, $lun)) {
|
|
print "WARNING: Failed to assign device '$device' to group '$group': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if (!defined($ASSIGNMENTS{$group})) {
|
|
my %assignments_t;
|
|
$ASSIGNMENTS{$group} = \%assignments_t;
|
|
}
|
|
|
|
my $_assignments = $ASSIGNMENTS{$group};
|
|
|
|
$$_assignments{$device} = $lun;
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub releaseDevice {
|
|
my $group = shift;
|
|
my $device = shift;
|
|
|
|
if (!defined($GROUPS{$group})) {
|
|
print "WARNING: Failed to release device '$device' from group '$group', group does not exist.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
if (!defined($$DEVICES{$device})) {
|
|
print "WARNING: Failed to release device '$device', device not defined.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Release virtual device '$device' from group '$group'..\n";
|
|
|
|
if ($SCST->removeDeviceFromGroup($device, $group)) {
|
|
print "WARNING: Failed to release device '$device' from group '$group': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
my $_assignments = $ASSIGNMENTS{$group};
|
|
|
|
undef $$_assignments{$device};
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub clearDevices {
|
|
my $group = shift;
|
|
|
|
if (!defined($GROUPS{$group})) {
|
|
print "WARNING: Failed to clear devices from group '$group', group does not exist.\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
print "\t-> Clear virtual devices from group '$group'..\n";
|
|
|
|
if ($SCST->clearGroupDevices($group)) {
|
|
print "WARNING: Failed to clear devices from group '$group': ".
|
|
$SCST->errorString()."\n";
|
|
return $TRUE;
|
|
}
|
|
|
|
undef $ASSIGNMENTS{$group};
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub targets {
|
|
my %targets;
|
|
my %fcards;
|
|
|
|
my $root = new IO::Dir $_FC_CLASS_ if (-d $_FC_CLASS_);
|
|
|
|
if ($root) {
|
|
while (my $entry = $root->read()) {
|
|
next if (($entry eq '.') || ($entry eq '..'));
|
|
|
|
my $io = new IO::File "$_FC_CLASS_/$entry/port_name", O_RDONLY;
|
|
|
|
if ($io) {
|
|
my $wwn = <$io>;
|
|
chomp $wwn;
|
|
close $io;
|
|
|
|
$fcards{$entry} = $wwn;
|
|
}
|
|
}
|
|
}
|
|
|
|
$root = new IO::Dir $_SCSI_CLASS_ if (-d $_SCSI_CLASS_);
|
|
|
|
if ($root) {
|
|
while (my $entry = $root->read()) {
|
|
next if (($entry eq '.') || ($entry eq '..'));
|
|
|
|
my $io = new IO::File "$_SCSI_CLASS_/$entry/target_mode_enabled", O_RDONLY;
|
|
|
|
if ($io) {
|
|
my $enabled = <$io>;
|
|
chomp $enabled;
|
|
close $io;
|
|
|
|
$targets{$entry}->{'path'} = "$_SCSI_CLASS_/$entry/target_mode_enabled";
|
|
$targets{$entry}->{'enabled'} = $enabled;
|
|
$targets{$entry}->{'qla_isp'} = $FALSE;
|
|
|
|
if ($fcards{$entry}) {
|
|
$targets{$fcards{$entry}}->{'enabled'} = $enabled;
|
|
$targets{$fcards{$entry}}->{'path'} =
|
|
"$_SCSI_CLASS_/$entry/target_mode_enabled";
|
|
$targets{$entry}->{'duplicate'} = $TRUE;
|
|
} else {
|
|
$targets{$entry}->{'duplicate'} = $FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$root = new IO::Dir $_SCSI_ISP_ if (-d $_SCSI_ISP_);
|
|
|
|
if ($root) {
|
|
while (my $entry = $root->read()) {
|
|
next if (($entry eq '.') || ($entry eq '..'));
|
|
|
|
local $/;
|
|
my $io = new IO::File "$_SCSI_ISP_/$entry", O_RDONLY;
|
|
|
|
if ($io) {
|
|
my $wwn;
|
|
my $fstr;
|
|
my $enabled2;
|
|
|
|
$fstr = <$io>;
|
|
close $io;
|
|
|
|
($wwn) = ($fstr =~ '.*?Port WWN +([^\ ]+) .*');
|
|
$fcards{$entry} = $wwn;
|
|
|
|
$io = new IO::File "$_SCSITGT_QLAISP_/$entry", O_RDONLY;
|
|
if ($io) {
|
|
$fstr = <$io>;
|
|
close $io;
|
|
|
|
($enabled2) = ($fstr =~ '[^\n]+\n *\d *: *(\d)');
|
|
$targets{$entry}->{'path'} = "$_SCSITGT_QLAISP_/$entry";
|
|
$targets{$entry}->{'enabled'} = $enabled2;
|
|
$targets{$entry}->{'qla_isp'} = $TRUE;
|
|
|
|
if ($fcards{$entry}) {
|
|
$targets{$fcards{$entry}}->{'enabled'} = $enabled2;
|
|
$targets{$fcards{$entry}}->{'path'} = "$_SCSITGT_QLAISP_/$entry";
|
|
$targets{$fcards{$entry}}->{'qla_isp'} = $TRUE;
|
|
$targets{$entry}->{'duplicate'} = $TRUE;
|
|
} else {
|
|
$targets{$entry}->{'duplicate'} = $FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return \%targets;
|
|
}
|
|
|
|
sub targetEnabled {
|
|
my $target = shift;
|
|
|
|
return undef if (!defined($$TARGETS{$target}));
|
|
return $$TARGETS{$target}->{'enabled'};
|
|
}
|
|
|
|
sub enableTarget {
|
|
my $target = shift;
|
|
my $enable = shift;
|
|
|
|
$target = unformatTarget($target);
|
|
|
|
return undef if (!defined($$TARGETS{$target}));
|
|
|
|
my $io = new IO::File $$TARGETS{$target}->{'path'}, O_WRONLY;
|
|
return $TRUE if (!$io);
|
|
|
|
print $enable ? "\t-> Enabling" : "\t-> Disabling";
|
|
print " target mode for SCST host '$target'.\n";
|
|
|
|
if ($_DEBUG_) {
|
|
print "DBG($$): ".$$TARGETS{$target}->{'path'}." -> $enable\n\n";
|
|
} else {
|
|
if ($$TARGETS{$target}->{'qla_isp'} == $FALSE) {
|
|
print $io $enable;
|
|
} else {
|
|
print $io $enable ? "enable all" : "disable all";
|
|
}
|
|
}
|
|
|
|
close $io;
|
|
|
|
$$TARGETS{$target}->{'enabled'} = $enable;
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
sub readConfig {
|
|
my $confile = shift;
|
|
my %config;
|
|
my $section;
|
|
my $last_section;
|
|
my $arg;
|
|
my $last_arg;
|
|
my %empty;
|
|
|
|
my $io = new IO::File $confile, O_RDONLY;
|
|
|
|
die("FATAL: Unable to open specified configuration file $confile: $!\n") if (!$io);
|
|
|
|
while (my $line = <$io>) {
|
|
($line, undef) = split(/\#/, $line, 2);
|
|
$line = cleanupString($line);
|
|
|
|
if ($line =~ /^\[(.*)\]$/) {
|
|
($section, $arg) = split(/\s+/, $1, 2);
|
|
|
|
if ($last_arg && ($last_section ne $section) &&
|
|
!defined($config{$last_section}->{$last_arg})) {
|
|
$config{$last_section}->{$last_arg} = \%empty;
|
|
}
|
|
|
|
$last_arg = $arg;
|
|
$last_section = $section;
|
|
} elsif ($section && $arg && $line) {
|
|
my($parameter, $value) = split(/\s+/, $line, 2);
|
|
|
|
push @{$config{$section}->{$arg}->{$parameter}}, $value;
|
|
}
|
|
}
|
|
|
|
close $io;
|
|
|
|
return \%config;
|
|
}
|
|
|
|
sub cleanupString {
|
|
my $string = shift;
|
|
|
|
$string =~ s/^\s+//;
|
|
$string =~ s/\s+$//;
|
|
|
|
return $string;
|
|
}
|
|
|
|
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 unformatTarget {
|
|
my $target = shift;
|
|
|
|
if ($target =~ /^.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}/) {
|
|
$target =~ s/\://g;
|
|
$target = "0x$target";
|
|
}
|
|
|
|
$target =~ tr/A-Z/a-z/;
|
|
|
|
return $target;
|
|
}
|
|
|
|
sub validHandlerTypes {
|
|
my $type = shift;
|
|
my $buffer = "\n";
|
|
|
|
foreach my $handler (keys %_REVERSE_MAP_) {
|
|
$buffer .= "\t".$_REVERSE_MAP_{$handler}."\n" if ($SCST->handlerType($handler) == $type);
|
|
}
|
|
|
|
return $buffer;
|
|
}
|
|
|
|
# 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;
|
|
}
|