diff --git a/scstadmin/Makefile b/scstadmin/Makefile index db0f5d62e..d2fcf2e48 100644 --- a/scstadmin/Makefile +++ b/scstadmin/Makefile @@ -1,38 +1,42 @@ -MODULE_VERSION = 0.8.22 -TOOL = scstadmin +SCSTADMIN_DIR = scstadmin -SBINDIR := $(PREFIX)/usr/local/sbin INITDIR := $(PREFIX)/etc/init.d -all: perl-module +all: + cd $(SCSTADMIN_DIR) && $(MAKE) $@ install: - $(MAKE) -C scst-$(MODULE_VERSION) install - install -m 755 $(TOOL) $(DESTDIR)$(SBINDIR) - install -m 755 init.d/scst $(DESTDIR)$(INITDIR) - install -m 755 init.d/qla2x00t $(DESTDIR)$(INITDIR) + cd $(SCSTADMIN_DIR) && $(MAKE) $@ -/usr/lib/lsb/install_initd scst -/usr/lib/lsb/install_initd qla2x00t + install -m 755 init.d/scst $(DESTDIR)$(INITDIR) + install -m 755 init.d/qla2x00t $(DESTDIR)$(INITDIR) uninstall: -/usr/lib/lsb/remove_initd qla2x00t -/usr/lib/lsb/remove_initd scst -rm -f $(DESTDIR)$(PATH_INITD)/qla2x00t -rm -f $(DESTDIR)$(PATH_INITD)/scst - -rm -f $(DESTDIR)$(PATH_SBIN)/$(TOOL) - $(MAKE) -C scst-$(MODULE_VERSION) uninstall + cd $(SCSTADMIN_DIR) && $(MAKE) $@ perl-module: - @cd ./scst-$(MODULE_VERSION); \ - perl Makefile.PL; - $(MAKE) -C scst-$(MODULE_VERSION) + cd $(SCSTADMIN_DIR) && $(MAKE) $@ clean: - -$(MAKE) -C scst-$(MODULE_VERSION) clean + cd $(SCSTADMIN_DIR) && $(MAKE) $@ -distclean: clean - -rm -f scst-$(MODULE_VERSION)/Makefile.old +distclean: + cd $(SCSTADMIN_DIR) && $(MAKE) $@ -extraclean: distclean +extraclean: + cd $(SCSTADMIN_DIR) && $(MAKE) $@ -.PHONY: all install uninstall perl-module clean distclean extraclean +disable_proc: + -rm scstadmin + ln -s sysfs scstadmin + +enable_proc: + -rm scstadmin + ln -s procfs scstadmin + +.PHONY: all install uninstall perl-module clean distclean extraclean disable_proc enable_proc diff --git a/scstadmin/README b/scstadmin/README index f01ac5ece..ef48ce1d2 100644 --- a/scstadmin/README +++ b/scstadmin/README @@ -7,6 +7,10 @@ The perl module SCST::SCST is very generic and tries to handle error checking as The init script was written for debian but should work on most distributions. + + sysfs Use this version if you've disabled procfs support in SCST. + procfs This is the default version which uses the older procfs. + scst-0.8.22 This is the SCST Perl module required by scstadmin and scst_db. scst-0.9.00 This is the SCST Perl module to be used with SCST compiled for sysfs. Note, the current version of scstadmin will NOT yet @@ -16,9 +20,6 @@ The init script was written for debian but should work on most distributions. a configuration file. See scst.conf. For command help, #> scstadmin - scstadmin.sysfs This is the sysfs version of scstadmin, a complete rewrite. This - is VERY incomplete at this point so don't expect results. - old Script which configures SCST using configurations found in a database. See the examples directory database schema and example data. You will need to edit the @@ -48,10 +49,22 @@ NOTE: The init.d startup & shutdown scripts now depend on lsb-core. Ensure you h lsb-core installed or 'make install' will fail. Make sure /usr/lib/lsb/install_initd exists. +To enable the newer sysfs version: + + #> make disable_proc + #> make + #> make install + Getting Started: ================ +The following pertains to the older procfs based SCST. The new sysfs version is still +a work in progress, but should be mostly complete at this point. You may still use your +old scst.conf, however, I very much recommend you perform a -write_config and review +the resulting configuration file. + + The scstadmin script is much more functional than scst_db at this point but uses a standard text-based config file. The original thought behind scst_db was to write a daemon process which would except network connections and issue SCST commands. A diff --git a/scstadmin/procfs/Makefile b/scstadmin/procfs/Makefile new file mode 100644 index 000000000..9152d949b --- /dev/null +++ b/scstadmin/procfs/Makefile @@ -0,0 +1,29 @@ +MODULE_VERSION = 0.8.22 +TOOL = scstadmin + +SBINDIR := $(PREFIX)/usr/local/sbin + +all: perl-module + +install: + $(MAKE) -C scst-$(MODULE_VERSION) install + install -m 755 $(TOOL) $(DESTDIR)$(SBINDIR) + +uninstall: + -rm -f $(DESTDIR)$(PATH_SBIN)/$(TOOL) + $(MAKE) -C scst-$(MODULE_VERSION) uninstall + +perl-module: + @cd ./scst-$(MODULE_VERSION); \ + perl Makefile.PL; + $(MAKE) -C scst-$(MODULE_VERSION) + +clean: + -$(MAKE) -C scst-$(MODULE_VERSION) clean + +distclean: clean + -rm -f scst-$(MODULE_VERSION)/Makefile.old + +extraclean: distclean + +.PHONY: all install uninstall perl-module clean distclean extraclean diff --git a/scstadmin/scst-0.8.22/MANIFEST b/scstadmin/procfs/scst-0.8.22/MANIFEST similarity index 100% rename from scstadmin/scst-0.8.22/MANIFEST rename to scstadmin/procfs/scst-0.8.22/MANIFEST diff --git a/scstadmin/scst-0.8.22/Makefile.PL b/scstadmin/procfs/scst-0.8.22/Makefile.PL similarity index 100% rename from scstadmin/scst-0.8.22/Makefile.PL rename to scstadmin/procfs/scst-0.8.22/Makefile.PL diff --git a/scstadmin/scst-0.8.22/README b/scstadmin/procfs/scst-0.8.22/README similarity index 100% rename from scstadmin/scst-0.8.22/README rename to scstadmin/procfs/scst-0.8.22/README diff --git a/scstadmin/scst-0.8.22/lib/SCST/SCST.pm b/scstadmin/procfs/scst-0.8.22/lib/SCST/SCST.pm similarity index 100% rename from scstadmin/scst-0.8.22/lib/SCST/SCST.pm rename to scstadmin/procfs/scst-0.8.22/lib/SCST/SCST.pm diff --git a/scstadmin/scst_db/scst_db b/scstadmin/procfs/scst_db/scst_db similarity index 100% rename from scstadmin/scst_db/scst_db rename to scstadmin/procfs/scst_db/scst_db diff --git a/scstadmin/scst_db/scst_db.conf b/scstadmin/procfs/scst_db/scst_db.conf similarity index 100% rename from scstadmin/scst_db/scst_db.conf rename to scstadmin/procfs/scst_db/scst_db.conf diff --git a/scstadmin/scst_db/scst_schema.sql b/scstadmin/procfs/scst_db/scst_schema.sql similarity index 100% rename from scstadmin/scst_db/scst_schema.sql rename to scstadmin/procfs/scst_db/scst_schema.sql diff --git a/scstadmin/procfs/scstadmin b/scstadmin/procfs/scstadmin new file mode 100755 index 000000000..84bb2e1cf --- /dev/null +++ b/scstadmin/procfs/scstadmin @@ -0,0 +1,2058 @@ +#!/usr/bin/perl +$Version = 'SCST Configurator v1.0.11'; + +# Configures SCST +# +# Author: Mark R. Buechler +# License: GPLv2 +# Copyright (c) 2005-2009 Mark R. Buechler + +sub usage + { + die <<"EndUsage"; +$Version + +Usage: +General Operations + -config : Configure SCST given the specified configuration file. + -ClearConfig : Clear all SCST configuration. + -WriteConfig : Writes the current configuration out to the specified file. + -checkConfig : Checks the saved configuration in the specified file. + -sessions : List current initiator sessions. + +Target Driver Operations + -enable : Enable target mode for driver at specified WWN or host. + -disable : Disable target mode for driver at specified WWN or host. + -issuelip : Issue LIP on all target-enabled FC fabrics. + +Device Operations + -adddev : Adds a device to a handler. + -handler + -path + -options + -blocksize + -resyncdev : Resync the size of a device with the initiator(s). + -handler + -RemoveDev : Remove a device from a handler. + -handler + -SetT10DeviceId : Sets the T10 Device ID of a device. + -device + -handler + +User Operations + -adduser : Adds a user to a security group. + -group + -MoveUser : Moves a user from one security group to another. + -group + -to + -RemoveUser : Delete a user from a security group. + -group + -ClearUsers : Clear all users from a given security group. + -group + +Group Operations + -addgroup : Add a given group to available security groups. + -renamegroup : Renames a give group to a new name. + -to + -RemoveGroup : Remove a give group from available security groups. + +Assignment Operations + -assigndev : Assign a given device to a security group. + -group + -lun + -options + -ReplaceDev : Replaces a device assigned to a give LUN and group. + -group + -lun + -options + -ReleaseDev : Remove a given device from a security group. + -group + -ClearDevs : Clear all device assignments for a security group. + -group + +Options + -ForceConfig : 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. + +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 + + Setting the T10 Device ID of a device + scstadmin -SetT10DeviceId test_disk -device disk1 -handler vdisk + + Assign a device to a security group: + scstadmin -assigndev DISK01 -group HOST01 -lun 1 + + Rename a security group: + scstadmin -RenameGroup HOST01 -to SERVER01 + + Tell all initiators to rescan LUNs: + scstadmin -issuelip + +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 $_TGT_DEF_PREFIX_ = 'Default_'; +my $_TGT_TMP_PREFIX_ = 'TMP_GRP'; + +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 $sett10id; + 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 $device; + my $group; + my $options; + my $blocksize; + my $enable; + my $disable; + my $issuelip; + my $noprompt; + + 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, + 'SetT10DeviceId=s' => \$sett10id, + '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, + 'device=s' => \$device, + 'group=s' => \$group, + 'options=s' => \$options, + 'blocksize=s' => \$blocksize, + 'enable=s' => \$enable, + 'disable=s' => \$disable, + 'issuelip' => \$issuelip, + 'noprompt' => \$noprompt, + 'debug' => \$_DEBUG_)) { + &usage(); + } + + if ((defined($enable) && !$enable) || (defined($disable) && !$disable)) { + print "Argument -enable/-disable requires a WWN or host.\n\n"; + usage(); + } + + if (defined($issuelip) && ($enable || $disable)) { + print "Argument -issuelip cannot be used with -enable or -disable.\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 ($sett10id && (!$device || !$handler)) { + print "Please specify -device and -handler with -SetT10DeviceId.\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)); + $issuelip = $TRUE if (defined($issuelip)); + $noprompt = $TRUE if (defined($noprompt)); + + $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) + + defined($sett10id)) > 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, $issuelip, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser, + $moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup, + $assignDev, $replaceDev, $releaseDev, $sett10id, $clearDevs, $handler, $device, $group, + $options, $blocksize, $applyConfig, $forceConfig, $clearConfig, $writeConfig, $checkConfig, + $showSessions, $noprompt); +} + +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, $issuelip, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser, + $moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup, + $assignDev, $replaceDev, $releaseDev, $sett10id, $clearDevs, $handler, $device, $group, + $options, $blocksize, $applyConfig, $forceConfig, $clearConfig, $writeConfig, $checkConfig, + $showSessions, $noprompt) = 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); + + if (!$noprompt) { + 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($noprompt); + 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; + }; + $sett10id && do { + $rc = setT10DeviceId($handler, $device, $sett10id); + 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; + }; + $issuelip && do { + $rc = issueLIP(); + last SWITCH; + }; + + print "No valid operations specified.\n"; + usage(); + exit $TRUE; + } + + print "\nAll 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; + my $keep_config; + + my $config = readConfig($file, $TRUE); + + 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"; + + print $io "[OPTIONS]\n"; + print $io "#OPTION <1|0|YES|NO|TRUE|FALSE|VALUE>\n"; + print $io "# Copy configuration options during a -writeconfig\n"; + print $io "KEEP_CONFIG "; + + if (defined($config)) { + $keep_config = $$config{'OPTIONS'}->{'default'}->{'KEEP_CONFIG'}[0]; + } else { + $keep_config = $FALSE; + } + + if (!defined($config)) { + print $io "TRUE\n"; + } elsif (!$keep_config ) { + print $io "FALSE\n"; + } else { + print $io "TRUE\n"; + } + + print $io "# For FC targets, issue a LIP after every assignment change\n"; + print $io "ISSUE_LIP "; + + if (!$keep_config) { + print $io "FALSE\n"; + } else { + print $io ($$config{'OPTIONS'}->{'default'}->{'ISSUE_LIP'}[0] ? "TRUE\n" : "FALSE\n"); + } + + print $io "\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 ,"; + if ($handler == $SCST::SCST::VDISK_TYPE) { + print $io ",,,\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 ",".$$devices{$device}->{'T10_DEVICE_ID'}; + print $io "\n"; + } + + print $io "\n"; + } + } + + # User configuration + foreach my $group (sort keys %USERS) { + print $io "[GROUP $group]\n"; + print $io "#USER \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 ,,\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 \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 $assign_changes = 0; + my $targets_changed = $FALSE; + + my %used_devs; + my %used_users; + my %used_assignments; + my %empty; + + my %seen_users; + + my %rename_group; + + my $issue_lip = $$config{'OPTIONS'}->{'default'}->{'ISSUE_LIP'}[0]; + + # 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'}}) { + my %seen_luns; + + foreach my $device (@{$$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) { + my($vname, $arg) = split(/\,/, $device, 2); + $vname = cleanupString($vname); + my($lun, $options) = split(/\,/, $arg); + if ($seen_luns{$lun}) { + print "\t-> FATAL: Configuration invalid. Group '$group' has multiple ". + "devices assigned to LUN $lun.\n"; + exit 1; + } + $used_assignments{$group}->{$vname} = $arg; + $seen_luns{$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++; + $assign_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 (defined($used_assignments{$group}->{$device}) && + ($$_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) { + my $_lun = $$_assignments{$device}; + my $replace_dev = findAssignedLun($used_assignments{$group}, $_lun); + + if (defined($replace_dev) && ($replace_dev ne $device)) { + print ", replacing with device '$replace_dev'.\n"; + + if (replaceDevice($group, $replace_dev, $_lun)) { + $errs++; + } else { + $changes++; + $assign_changes++; + } + } else { + print ", releasing.\n"; + if (releaseDevice($group, $device)) { + $errs++; + } else { + $changes++; + $assign_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 "\nApplying 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, $t10_id) = 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++; + } + + if ($t10_id ne '') { + if (setT10DeviceId($_handler, $vname, $t10_id)) { + $errs++; + } else { + $changes++; + } + } + } + } + } + + # Create new groups and add users.. + foreach my $group (keys %used_users) { + if (!defined($USERS{$group})) { + if ($group =~ /^$_TGT_DEF_PREFIX_/) { + my $tmp_group = randomGroup(); + + if (!defined($tmp_group)) { + print "\t-> WARNING: Unable to find a free temporary group for '$group', ". + "using the original group name instead.\n"; + + } else { + print "\t-> Using temporary group '$tmp_group' for group '$group'.\n"; + + $rename_group{$tmp_group} = $group; + $used_users{$tmp_group} = $used_users{$group}; + $group = $tmp_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 { + my $replace_dev = findAssignedLun($_assignments, $lun); + + if (defined($replace_dev) && ($vname ne $replace_dev)) { + print "\t-> WARNING: Use -ForceConfig to replace device '$replace_dev' ". + "with device '$vname' for group '$group'.\n" if (!$force); + next; + } + + 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++; + $assign_changes++; + } + } + } + } + } + + foreach my $tmp_group (keys %rename_group) { + my $group = $rename_group{$tmp_group}; + print "\t-> Processing temporary group '$tmp_group'.\n"; + + renameGroup($tmp_group, $group); + $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++; + $targets_changed = $TRUE; + } + } 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++; + $targets_changed = $TRUE; + } + } else { + print ".\n"; + $changes++; + } + } + } + } + + if ($issue_lip && $assign_changes && !$targets_changed) { + print "\nMaking initiators aware of assignment changes..\n\n"; + issueLIP(); + } + + print "\n\nEncountered $errs error(s) while processing.\n" if ($errs); + + if ($check) { + print "\nConfiguration checked, $changes difference(s) found with working configuration.\n"; + } else { + $changes = 0 if ($_DEBUG_); + print "\nConfiguration applied, $changes changes made.\n"; + } + + return $TRUE if ($errs); + return $FALSE; +} + +sub clearConfiguration { + my $noprompt = shift; + my $errs; + + if (!$noprompt) { + 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 setT10DeviceId { + my $handler = shift; + my $device = shift; + my $t10_id = 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-> Changing T10 Device ID of virtual device '$device' to '$t10_id'..\n"; + + if ($SCST->setT10DeviceId($_handler, $device, $t10_id)) { + print "WARNING: Failed to changing T10 Device ID of virtual device '$device': ". + $SCST->errorString()."\n"; + return $TRUE; + } + + 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"; + + if (-f "$_FC_CLASS_/$entry/issue_lip") { + $targets{$fcards{$entry}}->{'ilip'} = "$_FC_CLASS_/$entry/issue_lip"; + } + + $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 issueLIP { + my $lip_issued; + + foreach my $target (keys %{$TARGETS}) { + next if ($$TARGETS{$target}->{'duplicate'}); + next if (!$$TARGETS{$target}->{'enabled'}); + + if (defined($$TARGETS{$target}->{'ilip'})) { + my $io = new IO::File $$TARGETS{$target}->{'ilip'}, O_WRONLY; + return $TRUE if (!$io); + + print "\t-> Issuing LIP for target '".formatTarget($target)."': "; + + if ($_DEBUG_) { + print "DBG($$): ".$$TARGETS{$target}->{'ilip'}." -> $TRUE\n\n"; + } else { + print $io $TRUE; + } + + print "done.\n"; + + $lip_issued = $TRUE; + } + } + + print "\t-> WARNING: This target driver does not support issuing LIPs.\n\n" + if (!$lip_issued); +} + +sub readConfig { + 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 = cleanupString($line); + + 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($parameter, $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}->{$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 findAssignedLun { + my $associations = shift; + my $lun = shift; + + return undef if (!defined($lun)); + + foreach my $device (keys %{$associations}) { + if ($$associations{$device} == $lun) { + return $device; + } + } + + 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; +} + +sub randomGroup { + my $tmp_group; + my $retry = 0; + + while (($retry < 10000) && (!$tmp_group || $SCST->groupExists($tmp_group))) { + my $id = int(rand(10000)); + + $tmp_group = $_TGT_TMP_PREFIX_.$id; + + $retry++; + } + + return undef if ($SCST->groupExists($tmp_group)); + return $tmp_group; +} + +# 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; +} diff --git a/scstadmin/scstadmin b/scstadmin/scstadmin deleted file mode 100755 index 84bb2e1cf..000000000 --- a/scstadmin/scstadmin +++ /dev/null @@ -1,2058 +0,0 @@ -#!/usr/bin/perl -$Version = 'SCST Configurator v1.0.11'; - -# Configures SCST -# -# Author: Mark R. Buechler -# License: GPLv2 -# Copyright (c) 2005-2009 Mark R. Buechler - -sub usage - { - die <<"EndUsage"; -$Version - -Usage: -General Operations - -config : Configure SCST given the specified configuration file. - -ClearConfig : Clear all SCST configuration. - -WriteConfig : Writes the current configuration out to the specified file. - -checkConfig : Checks the saved configuration in the specified file. - -sessions : List current initiator sessions. - -Target Driver Operations - -enable : Enable target mode for driver at specified WWN or host. - -disable : Disable target mode for driver at specified WWN or host. - -issuelip : Issue LIP on all target-enabled FC fabrics. - -Device Operations - -adddev : Adds a device to a handler. - -handler - -path - -options - -blocksize - -resyncdev : Resync the size of a device with the initiator(s). - -handler - -RemoveDev : Remove a device from a handler. - -handler - -SetT10DeviceId : Sets the T10 Device ID of a device. - -device - -handler - -User Operations - -adduser : Adds a user to a security group. - -group - -MoveUser : Moves a user from one security group to another. - -group - -to - -RemoveUser : Delete a user from a security group. - -group - -ClearUsers : Clear all users from a given security group. - -group - -Group Operations - -addgroup : Add a given group to available security groups. - -renamegroup : Renames a give group to a new name. - -to - -RemoveGroup : Remove a give group from available security groups. - -Assignment Operations - -assigndev : Assign a given device to a security group. - -group - -lun - -options - -ReplaceDev : Replaces a device assigned to a give LUN and group. - -group - -lun - -options - -ReleaseDev : Remove a given device from a security group. - -group - -ClearDevs : Clear all device assignments for a security group. - -group - -Options - -ForceConfig : 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. - -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 - - Setting the T10 Device ID of a device - scstadmin -SetT10DeviceId test_disk -device disk1 -handler vdisk - - Assign a device to a security group: - scstadmin -assigndev DISK01 -group HOST01 -lun 1 - - Rename a security group: - scstadmin -RenameGroup HOST01 -to SERVER01 - - Tell all initiators to rescan LUNs: - scstadmin -issuelip - -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 $_TGT_DEF_PREFIX_ = 'Default_'; -my $_TGT_TMP_PREFIX_ = 'TMP_GRP'; - -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 $sett10id; - 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 $device; - my $group; - my $options; - my $blocksize; - my $enable; - my $disable; - my $issuelip; - my $noprompt; - - 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, - 'SetT10DeviceId=s' => \$sett10id, - '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, - 'device=s' => \$device, - 'group=s' => \$group, - 'options=s' => \$options, - 'blocksize=s' => \$blocksize, - 'enable=s' => \$enable, - 'disable=s' => \$disable, - 'issuelip' => \$issuelip, - 'noprompt' => \$noprompt, - 'debug' => \$_DEBUG_)) { - &usage(); - } - - if ((defined($enable) && !$enable) || (defined($disable) && !$disable)) { - print "Argument -enable/-disable requires a WWN or host.\n\n"; - usage(); - } - - if (defined($issuelip) && ($enable || $disable)) { - print "Argument -issuelip cannot be used with -enable or -disable.\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 ($sett10id && (!$device || !$handler)) { - print "Please specify -device and -handler with -SetT10DeviceId.\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)); - $issuelip = $TRUE if (defined($issuelip)); - $noprompt = $TRUE if (defined($noprompt)); - - $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) + - defined($sett10id)) > 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, $issuelip, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser, - $moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup, - $assignDev, $replaceDev, $releaseDev, $sett10id, $clearDevs, $handler, $device, $group, - $options, $blocksize, $applyConfig, $forceConfig, $clearConfig, $writeConfig, $checkConfig, - $showSessions, $noprompt); -} - -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, $issuelip, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser, - $moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup, - $assignDev, $replaceDev, $releaseDev, $sett10id, $clearDevs, $handler, $device, $group, - $options, $blocksize, $applyConfig, $forceConfig, $clearConfig, $writeConfig, $checkConfig, - $showSessions, $noprompt) = 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); - - if (!$noprompt) { - 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($noprompt); - 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; - }; - $sett10id && do { - $rc = setT10DeviceId($handler, $device, $sett10id); - 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; - }; - $issuelip && do { - $rc = issueLIP(); - last SWITCH; - }; - - print "No valid operations specified.\n"; - usage(); - exit $TRUE; - } - - print "\nAll 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; - my $keep_config; - - my $config = readConfig($file, $TRUE); - - 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"; - - print $io "[OPTIONS]\n"; - print $io "#OPTION <1|0|YES|NO|TRUE|FALSE|VALUE>\n"; - print $io "# Copy configuration options during a -writeconfig\n"; - print $io "KEEP_CONFIG "; - - if (defined($config)) { - $keep_config = $$config{'OPTIONS'}->{'default'}->{'KEEP_CONFIG'}[0]; - } else { - $keep_config = $FALSE; - } - - if (!defined($config)) { - print $io "TRUE\n"; - } elsif (!$keep_config ) { - print $io "FALSE\n"; - } else { - print $io "TRUE\n"; - } - - print $io "# For FC targets, issue a LIP after every assignment change\n"; - print $io "ISSUE_LIP "; - - if (!$keep_config) { - print $io "FALSE\n"; - } else { - print $io ($$config{'OPTIONS'}->{'default'}->{'ISSUE_LIP'}[0] ? "TRUE\n" : "FALSE\n"); - } - - print $io "\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 ,"; - if ($handler == $SCST::SCST::VDISK_TYPE) { - print $io ",,,\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 ",".$$devices{$device}->{'T10_DEVICE_ID'}; - print $io "\n"; - } - - print $io "\n"; - } - } - - # User configuration - foreach my $group (sort keys %USERS) { - print $io "[GROUP $group]\n"; - print $io "#USER \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 ,,\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 \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 $assign_changes = 0; - my $targets_changed = $FALSE; - - my %used_devs; - my %used_users; - my %used_assignments; - my %empty; - - my %seen_users; - - my %rename_group; - - my $issue_lip = $$config{'OPTIONS'}->{'default'}->{'ISSUE_LIP'}[0]; - - # 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'}}) { - my %seen_luns; - - foreach my $device (@{$$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) { - my($vname, $arg) = split(/\,/, $device, 2); - $vname = cleanupString($vname); - my($lun, $options) = split(/\,/, $arg); - if ($seen_luns{$lun}) { - print "\t-> FATAL: Configuration invalid. Group '$group' has multiple ". - "devices assigned to LUN $lun.\n"; - exit 1; - } - $used_assignments{$group}->{$vname} = $arg; - $seen_luns{$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++; - $assign_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 (defined($used_assignments{$group}->{$device}) && - ($$_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) { - my $_lun = $$_assignments{$device}; - my $replace_dev = findAssignedLun($used_assignments{$group}, $_lun); - - if (defined($replace_dev) && ($replace_dev ne $device)) { - print ", replacing with device '$replace_dev'.\n"; - - if (replaceDevice($group, $replace_dev, $_lun)) { - $errs++; - } else { - $changes++; - $assign_changes++; - } - } else { - print ", releasing.\n"; - if (releaseDevice($group, $device)) { - $errs++; - } else { - $changes++; - $assign_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 "\nApplying 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, $t10_id) = 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++; - } - - if ($t10_id ne '') { - if (setT10DeviceId($_handler, $vname, $t10_id)) { - $errs++; - } else { - $changes++; - } - } - } - } - } - - # Create new groups and add users.. - foreach my $group (keys %used_users) { - if (!defined($USERS{$group})) { - if ($group =~ /^$_TGT_DEF_PREFIX_/) { - my $tmp_group = randomGroup(); - - if (!defined($tmp_group)) { - print "\t-> WARNING: Unable to find a free temporary group for '$group', ". - "using the original group name instead.\n"; - - } else { - print "\t-> Using temporary group '$tmp_group' for group '$group'.\n"; - - $rename_group{$tmp_group} = $group; - $used_users{$tmp_group} = $used_users{$group}; - $group = $tmp_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 { - my $replace_dev = findAssignedLun($_assignments, $lun); - - if (defined($replace_dev) && ($vname ne $replace_dev)) { - print "\t-> WARNING: Use -ForceConfig to replace device '$replace_dev' ". - "with device '$vname' for group '$group'.\n" if (!$force); - next; - } - - 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++; - $assign_changes++; - } - } - } - } - } - - foreach my $tmp_group (keys %rename_group) { - my $group = $rename_group{$tmp_group}; - print "\t-> Processing temporary group '$tmp_group'.\n"; - - renameGroup($tmp_group, $group); - $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++; - $targets_changed = $TRUE; - } - } 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++; - $targets_changed = $TRUE; - } - } else { - print ".\n"; - $changes++; - } - } - } - } - - if ($issue_lip && $assign_changes && !$targets_changed) { - print "\nMaking initiators aware of assignment changes..\n\n"; - issueLIP(); - } - - print "\n\nEncountered $errs error(s) while processing.\n" if ($errs); - - if ($check) { - print "\nConfiguration checked, $changes difference(s) found with working configuration.\n"; - } else { - $changes = 0 if ($_DEBUG_); - print "\nConfiguration applied, $changes changes made.\n"; - } - - return $TRUE if ($errs); - return $FALSE; -} - -sub clearConfiguration { - my $noprompt = shift; - my $errs; - - if (!$noprompt) { - 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 setT10DeviceId { - my $handler = shift; - my $device = shift; - my $t10_id = 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-> Changing T10 Device ID of virtual device '$device' to '$t10_id'..\n"; - - if ($SCST->setT10DeviceId($_handler, $device, $t10_id)) { - print "WARNING: Failed to changing T10 Device ID of virtual device '$device': ". - $SCST->errorString()."\n"; - return $TRUE; - } - - 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"; - - if (-f "$_FC_CLASS_/$entry/issue_lip") { - $targets{$fcards{$entry}}->{'ilip'} = "$_FC_CLASS_/$entry/issue_lip"; - } - - $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 issueLIP { - my $lip_issued; - - foreach my $target (keys %{$TARGETS}) { - next if ($$TARGETS{$target}->{'duplicate'}); - next if (!$$TARGETS{$target}->{'enabled'}); - - if (defined($$TARGETS{$target}->{'ilip'})) { - my $io = new IO::File $$TARGETS{$target}->{'ilip'}, O_WRONLY; - return $TRUE if (!$io); - - print "\t-> Issuing LIP for target '".formatTarget($target)."': "; - - if ($_DEBUG_) { - print "DBG($$): ".$$TARGETS{$target}->{'ilip'}." -> $TRUE\n\n"; - } else { - print $io $TRUE; - } - - print "done.\n"; - - $lip_issued = $TRUE; - } - } - - print "\t-> WARNING: This target driver does not support issuing LIPs.\n\n" - if (!$lip_issued); -} - -sub readConfig { - 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 = cleanupString($line); - - 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($parameter, $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}->{$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 findAssignedLun { - my $associations = shift; - my $lun = shift; - - return undef if (!defined($lun)); - - foreach my $device (keys %{$associations}) { - if ($$associations{$device} == $lun) { - return $device; - } - } - - 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; -} - -sub randomGroup { - my $tmp_group; - my $retry = 0; - - while (($retry < 10000) && (!$tmp_group || $SCST->groupExists($tmp_group))) { - my $id = int(rand(10000)); - - $tmp_group = $_TGT_TMP_PREFIX_.$id; - - $retry++; - } - - return undef if ($SCST->groupExists($tmp_group)); - return $tmp_group; -} - -# 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; -} diff --git a/scstadmin/scstadmin b/scstadmin/scstadmin new file mode 120000 index 000000000..af8e7f827 --- /dev/null +++ b/scstadmin/scstadmin @@ -0,0 +1 @@ +procfs \ No newline at end of file diff --git a/scstadmin/sysfs/Makefile b/scstadmin/sysfs/Makefile new file mode 100644 index 000000000..27618d6ba --- /dev/null +++ b/scstadmin/sysfs/Makefile @@ -0,0 +1,29 @@ +MODULE_VERSION = 0.9.00 +TOOL = scstadmin + +SBINDIR := $(PREFIX)/usr/local/sbin + +all: perl-module + +install: + $(MAKE) -C scst-$(MODULE_VERSION) install + install -m 755 $(TOOL) $(DESTDIR)$(SBINDIR) + +uninstall: + -rm -f $(DESTDIR)$(PATH_SBIN)/$(TOOL) + $(MAKE) -C scst-$(MODULE_VERSION) uninstall + +perl-module: + @cd ./scst-$(MODULE_VERSION); \ + perl Makefile.PL; + $(MAKE) -C scst-$(MODULE_VERSION) + +clean: + -$(MAKE) -C scst-$(MODULE_VERSION) clean + +distclean: clean + -rm -f scst-$(MODULE_VERSION)/Makefile.old + +extraclean: distclean + +.PHONY: all install uninstall perl-module clean distclean extraclean diff --git a/scstadmin/scst-0.9.00/MANIFEST b/scstadmin/sysfs/scst-0.9.00/MANIFEST similarity index 100% rename from scstadmin/scst-0.9.00/MANIFEST rename to scstadmin/sysfs/scst-0.9.00/MANIFEST diff --git a/scstadmin/scst-0.9.00/Makefile.PL b/scstadmin/sysfs/scst-0.9.00/Makefile.PL similarity index 100% rename from scstadmin/scst-0.9.00/Makefile.PL rename to scstadmin/sysfs/scst-0.9.00/Makefile.PL diff --git a/scstadmin/scst-0.9.00/README b/scstadmin/sysfs/scst-0.9.00/README similarity index 100% rename from scstadmin/scst-0.9.00/README rename to scstadmin/sysfs/scst-0.9.00/README diff --git a/scstadmin/scst-0.9.00/lib/SCST/SCST.pm b/scstadmin/sysfs/scst-0.9.00/lib/SCST/SCST.pm similarity index 100% rename from scstadmin/scst-0.9.00/lib/SCST/SCST.pm rename to scstadmin/sysfs/scst-0.9.00/lib/SCST/SCST.pm diff --git a/scstadmin/scstadmin.sysfs b/scstadmin/sysfs/scstadmin similarity index 100% rename from scstadmin/scstadmin.sysfs rename to scstadmin/sysfs/scstadmin