Files
scst/scstadmin/scstadmin
T
Mark Buechler c76190e675 - Remove unused references to handler IOs that don't exist and cleanup the write
configuration function to only write vdisk and vcdrom devices. All other devices
  are automatically claimed by their handler module. I'm not sure how this will work
  with devices we wish to change handlers for.



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1110 d57e44dd-8a1f-0410-8b47-8ef2f437770f
2009-09-17 21:04:39 +00:00

1810 lines
45 KiB
Perl
Executable File

#!/usr/bin/perl
$Version = 'SCST Configurator v1.0.9';
# 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>
-MoveUser <user> : Moves a user from one security group to another.
-group <group 1>
-to <group 2>
-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.
-renamegroup <group> : Renames a give group to a new name.
-to <new group>
-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>
-options <options>
-ReplaceDev <new dev>: Replaces a device assigned to a give LUN and group.
-group <group>
-lun <lun>
-options <options>
-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
Available Options for assign and replace:
READ_ONLY
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
Rename a security group:
scstadmin -RenameGroup HOST01 -to SERVER01
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 $replaceDev;
my $removeDev;
my $addUser;
my $moveUser;
my $removeUser;
my $clearUsers;
my $addGroup;
my $toGroup;
my $renameGroup;
my $removeGroup;
my $assignDev;
my $replaceDev;
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,
'ReplaceDev=s' => \$replaceDev,
'RemoveDev=s' => \$removeDev,
'lun=s' => \$devLun,
'adduser=s' => \$addUser,
'MoveUser=s' => \$moveUser,
'RemoveUser=s' => \$removeUser,
'ClearUsers' => \$clearUsers,
'addgroup=s' => \$addGroup,
'to=s' => \$toGroup,
'RemoveGroup=s' => \$removeGroup,
'renamegroup=s' => \$renameGroup,
'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 ($moveUser && (!defined($group) || !defined($toGroup))) {
print "Please specify -group and -to with -MoveUser.\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 ($renameGroup && !defined($toGroup)) {
print "Please specify -to with -renamegroup.\n\n";
usage();
}
if ($assignDev && !defined($group)) {
print "Please specify -group with -assigndev.\n\n";
usage();
}
if ($replaceDev && (!defined($group) || !defined($devLun))) {
print "Please specify -group and -lun with -ReplaceDev.\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,
$moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup,
$assignDev, $replaceDev, $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,
$moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup,
$assignDev, $replaceDev, $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, $TRUE, $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;
};
$moveUser && do {
$rc = moveUser($group, $moveUser, $toGroup);
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;
};
$renameGroup && do {
$rc = renameGroup($renameGroup, $toGroup);
last SWITCH;
};
$removeGroup && do {
$rc = removeGroup($removeGroup);
last SWITCH;
};
$assignDev && do {
$rc = assignDevice($group, $assignDev, $devLun, $options);
last SWITCH;
};
$replaceDev && do {
$rc = replaceDevice($group, $replaceDev, $devLun, $options);
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";
print $io "# NOTE: Options are pipe (|) seperated.\n\n";
# Device information
foreach my $handler (sort keys %HANDLERS) {
if ($SCST->handlerType($handler) == $SCST::SCST::IOTYPE_VIRTUAL) {
print $io "[HANDLER ".$_REVERSE_MAP_{$handler}."]\n";
print $io "#DEVICE <vdisk name>,<device path>";
if ($handler == $SCST::SCST::VDISK_TYPE) {
print $io ",<options>,<block size>\n";
} else {
print $io "\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>,<options>\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;
my %seen_users;
# 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'}}) {
if (defined($seen_users{$user})) {
print "\t-> FATAL: Configuration invalid. User '$user' is in more ".
"than one group!\n";
exit 1;
}
$used_users{$group}->{$user}++;
$seen_users{$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, $arg) = split(/\,/, $device, 2);
$vname = cleanupString($vname);
$used_assignments{$group}->{$vname} = $arg;
}
}
# 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) {
# Are we moving this user to another group?
my $new_group = findUserGroup($user, $config);
if ($new_group && ($new_group ne $group)) {
print ", moving to group '$new_group'.\n";
if (moveUser($group, $user, $new_group)) {
$errs++;
} else {
$changes++;
}
} else {
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})) {
my $move_group = findUserGroupInCurrent($user);
if ($move_group) {
print "\t-> WARNING: Use -ForceConfig to move user '$user' ".
"from group '$move_group' to group '$group'.\n" if (!$force);
next;
}
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 $arg = $used_assignments{$group}->{$vname};
my($lun, $options) = split(/\,/, $arg);
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, $options)) {
$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 renameGroup {
my $group = shift;
my $toGroup = shift;
if (defined($GROUPS{$toGroup})) {
print "WARNING: Group '$toGroup' already exists.\n";
return $TRUE;
}
print "\t-> Renaming security group '$group' to '$toGroup'..\n";
if ($SCST->renameGroup($group, $toGroup)) {
print "WARNING: Failed to rename security group '$group' to ".
"'$toGroup': ".$SCST->errorString()."\n";
return $TRUE;
}
delete $GROUPS{$group};
$GROUPS{$toGroup}++;
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 moveUser {
my $group = shift;
my $user = shift;
my $toGroup = shift;
if (!defined($GROUPS{$group})) {
print "WARNING: Failed to move user '$user' from group '$group', group does not exist.\n";
return $TRUE;
}
if (defined($USERS{$toGroup}->{$user})) {
print "WARNING: User '$user' already exists in security group '$toGroup'.\n";
return $TRUE;
}
print "\t-> Moving user '$user' from security group '$group' to security group '$toGroup'..\n";
if ($SCST->moveUser($user, $group, $toGroup)) {
print "WARNING: Failed to move user '$user' from security group '$group' to ".
"security group '$toGroup': ".$SCST->errorString()."\n";
return $TRUE;
}
delete $USERS{$group}->{$user};
$USERS{$toGroup}->{$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 $options = 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, $options)) {
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 replaceDevice {
my $group = shift;
my $newDevice = shift;
my $lun = shift;
my $options = 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;
}
}
if (!defined($$DEVICES{$newDevice})) {
print "WARNING: Unable to assign non-existant device '$newDevice' to group '$group'.\n";
return $TRUE;
}
if (${$allLuns{$group}}[$lun] eq $newDevice) {
print "ERROR: Device '$newDevice': Lun '$lun' is already assigned to device '$newDevice'.\n";
return $TRUE;
}
print "\t-> Replace device at LUN '$lun' in group '$group' with new device '$newDevice'..\n";
if ($SCST->replaceDeviceInGroup($newDevice, $group, $lun, $options)) {
print "WARNING: Failed to replace LUN '$lun' in group '$group' with new device '$newDevice': ".
$SCST->errorString()."\n";
return $TRUE;
}
if (!defined($ASSIGNMENTS{$group})) {
my %assignments_t;
$ASSIGNMENTS{$group} = \%assignments_t;
}
my $_assignments = $ASSIGNMENTS{$group};
delete $$_assignments{${$allLuns{$group}}[$lun]};
$$_assignments{$newDevice} = $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_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($parameter, $value) = split(/\s+/, $line, 2);
push @{$config{$section}->{$arg}->{$parameter}}, $value;
}
}
close $io;
return \%config;
}
sub findUserGroup {
my $user = shift;
my $config = shift;
foreach my $group (keys %{$$config{'GROUP'}}) {
foreach my $_user (@{$$config{'GROUP'}->{$group}->{'USER'}}) {
return $group if ($_user eq $user);
}
}
return undef;
}
sub findUserGroupInCurrent {
my $user = shift;
foreach my $group (keys %USERS) {
foreach my $_user (keys %{$USERS{$group}}) {
return $group if ($_user eq $user);
}
}
return undef;
}
sub findDeviceGroup {
my $device = shift;
my $config = shift;
foreach my $group (keys %{$$config{'ASSIGNMENT'}}) {
foreach my $device (@{$$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
my($vname, $arg) = split(/\,/, $device, 2);
$vname = cleanupString($vname);
return $group if ($vname eq $device);
}
}
return undef;
}
sub findDeviceGroupInCurrent {
my $device = shift;
return undef;
}
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;
}