2 $Version = 'SCST Configurator v1.0.9';
6 # Author: Mark R. Buechler
8 # Copyright (c) 2005-2009 Mark R. Buechler
17 -config <config> : Configure SCST given the specified configuration file.
18 -ClearConfig : Clear all SCST configuration.
19 -WriteConfig <file> : Writes the current configuration out to the specified file.
20 -checkConfig <file> : Checks the saved configuration in the specified file.
21 -sessions : List current initiator sessions.
23 Target Driver Operations
24 -enable <wwn|host> : Enable target mode for driver at specified WWN or host.
25 -disable <wwn|host> : Disable target mode for driver at specified WWN or host.
28 -adddev <device> : Adds a device to a handler.
33 -resyncdev <device> : Resync the size of a device with the initiator(s).
35 -RemoveDev <device> : Remove a device from a handler.
39 -adduser <user> : Adds a user to a security group.
41 -MoveUser <user> : Moves a user from one security group to another.
44 -RemoveUser <user> : Delete a user from a security group.
46 -ClearUsers : Clear all users from a given security group.
50 -addgroup <group> : Add a given group to available security groups.
51 -renamegroup <group> : Renames a give group to a new name.
53 -RemoveGroup <group> : Remove a give group from available security groups.
56 -assigndev <device> : Assign a given device to a security group.
60 -ReplaceDev <new dev>: Replaces a device assigned to a give LUN and group.
64 -ReleaseDev <device> : Remove a given device from a security group.
66 -ClearDevs : Clear all device assignments for a security group.
70 -ForceConfig : Force all configuration changes, even deletions (DANGER!).
72 Debugging (limited support)
73 -debug : Debug mode - don\'t do anything destructive.
76 disk, vdisk, disk_perf, cdrom, vcdrom, changer, modisk, modisk_perf, tape, tape_perf
78 Available Options for create and open:
79 WRITE_THROUGH, READ_ONLY, O_DIRECT, NULLIO, NV_CACHE, BLOCK_IO, REMOVABLE
81 Available Options for assign and replace:
85 Enable target mode for fibre card specifying its WWN
86 scstadmin -enable 50:06:0B:00:00:39:71:78
88 Disable target mode for SCSI host specifying host number
89 scstadmin -disable host4
91 Create a new security group:
92 scstadmin -addgroup HOST01
94 Create a device given an already existing disk file:
95 scstadmin -adddev DISK01 -handler vdisk -path /vdisks/disk01.dsk -options READ_ONLY,WRITE_THROUGH
97 Assign a device to a security group:
98 scstadmin -assigndev DISK01 -group HOST01 -lun 1
100 Rename a security group:
101 scstadmin -RenameGroup HOST01 -to SERVER01
113 my $_DEF_CONFIG_ = '/etc/scst.conf';
118 my $_MAX_LUNS_ = 255;
119 my $_DEFAULT_GROUP_ = 'Default';
121 my $_SCSI_CLASS_ = '/sys/class/scsi_host';
122 my $_FC_CLASS_ = '/sys/class/fc_host';
123 my $_SCSI_ISP_ = '/proc/scsi/isp';
124 my $_SCSITGT_QLAISP_ = '/proc/scsi_tgt/qla_isp';
126 my $_TGT_DEF_PREFIX_ = 'Default_';
127 my $_TGT_TMP_PREFIX_ = 'TMP_GRP';
138 my %_HANDLER_MAP_ = ('cdrom' => $SCST::SCST::CDROM_TYPE,
139 'changer' => $SCST::SCST::CHANGER_TYPE,
140 'disk' => $SCST::SCST::DISK_TYPE,
141 'vdisk' => $SCST::SCST::VDISK_TYPE,
142 'vcdrom' => $SCST::SCST::VCDROM_TYPE,
143 'disk_perf' => $SCST::SCST::DISKPERF_TYPE,
144 'modisk' => $SCST::SCST::MODISK_TYPE,
145 'modisk_perf' => $SCST::SCST::MODISKPERF_TYPE,
146 'tape' => $SCST::SCST::TAPE_TYPE,
147 'tape_perf' => $SCST::SCST::TAPEPERF_TYPE,
148 'processor' => $SCST::SCST::PROCESSOR_TYPE,
149 # Add in the dev_ names as well
150 'dev_cdrom' => $SCST::SCST::CDROM_TYPE,
151 'dev_changer' => $SCST::SCST::CHANGER_TYPE,
152 'dev_disk' => $SCST::SCST::DISK_TYPE,
153 'dev_disk_perf' => $SCST::SCST::DISKPERF_TYPE,
154 'dev_modisk' => $SCST::SCST::MODISK_TYPE,
155 'dev_modisk_perf' => $SCST::SCST::MODISKPERF_TYPE,
156 'dev_tape' => $SCST::SCST::TAPE_TYPE,
157 'dev_tape_perf' => $SCST::SCST::TAPEPERF_TYPE,
158 'dev_processor' => $SCST::SCST::PROCESSOR_TYPE);
160 my %_REVERSE_MAP_ = ($SCST::SCST::CDROM_TYPE => 'cdrom',
161 $SCST::SCST::CHANGER_TYPE => 'changer',
162 $SCST::SCST::DISK_TYPE => 'disk',
163 $SCST::SCST::VDISK_TYPE => 'vdisk',
164 $SCST::SCST::VCDROM_TYPE => 'vcdrom',
165 $SCST::SCST::DISKPERF_TYPE => 'disk_perf',
166 $SCST::SCST::MODISK_TYPE => 'modisk',
167 $SCST::SCST::MODISKPERF_TYPE => 'modisk_perf',
168 $SCST::SCST::TAPE_TYPE => 'tape',
169 $SCST::SCST::TAPEPERF_TYPE => 'tape_perf',
170 $SCST::SCST::PROCESSOR_TYPE => 'processor');
172 my %_HANDLER_TYPE_MAP_ = ($SCST::SCST::IOTYPE_PHYSICAL => 'physical',
173 $SCST::SCST::IOTYPE_VIRTUAL => 'virtual',
174 $SCST::SCST::IOTYPE_PERFORMANCE => 'performance');
176 $SIG{INT} = \&commitSuicide;
178 use vars qw($Version);
216 my $p = new Getopt::Long::Parser;
218 if (!$p->getoptions('config:s' => \$applyConfig,
219 'ClearConfig' => \$clearConfig,
220 'ForceConfig' => \$forceConfig,
221 'WriteConfig=s' => \$writeConfig,
222 'checkConfig=s' => \$checkConfig,
223 'sessions' => \$showSessions,
224 'adddev=s' => \$addDev,
225 'path=s' => \$devPath,
226 'ReplaceDev=s' => \$replaceDev,
227 'RemoveDev=s' => \$removeDev,
229 'adduser=s' => \$addUser,
230 'MoveUser=s' => \$moveUser,
231 'RemoveUser=s' => \$removeUser,
232 'ClearUsers' => \$clearUsers,
233 'addgroup=s' => \$addGroup,
235 'RemoveGroup=s' => \$removeGroup,
236 'renamegroup=s' => \$renameGroup,
237 'assigndev=s' => \$assignDev,
238 'resyncdev=s' => \$resyncDev,
239 'ReleaseDev=s' => \$releaseDev,
240 'ClearDevs' => \$clearDevs,
241 'handler=s' => \$handler,
242 'group=s' => \$group,
243 'options=s' => \$options,
244 'blocksize=s' => \$blocksize,
245 'enable=s' => \$enable,
246 'disable=s' => \$disable,
247 'debug' => \$_DEBUG_)) {
251 if ((defined($enable) && !$enable) || (defined($disable) && !$disable)) {
252 print "Argument -enable/-disable requires a WWN or host.\n\n";
256 if ($handler && !$_HANDLER_MAP_{$handler}) {
257 print "Invalid handler '$handler' specified. Available handlers are:\n\n";
258 foreach my $_handler (keys %_HANDLER_MAP_) {
259 print "\t$_handler\n";
265 if ($addDev && !($handler && $devPath)) {
266 print "Please specify -handler and -path with -adddev.\n\n";
270 if (defined($blocksize) && !$blocksize) {
271 print "Please specify bytes with -blocksize.\n\n";
275 if ($blocksize && !$addDev) {
276 print "Please specify -adddev with -blocksize.\n";
280 if (defined($forceConfig) && !defined($applyConfig)) {
281 print "Please specify -config with -ForceConfig.\n\n";
285 if ($resyncDev && !$handler) {
286 print "Please specify -handler with -resyncdev.\n\n";
290 if ($removeDev && !$handler) {
291 print "Please specify -handler with -RemoveDev.\n\n";
295 if ($addUser && !defined($group)) {
296 print "Please specify -group with -adduser.\n\n";
300 if ($moveUser && (!defined($group) || !defined($toGroup))) {
301 print "Please specify -group and -to with -MoveUser.\n\n";
305 if ($removeUser && !defined($group)) {
306 print "Please specify -group with -RemoveUser.\n\n";
310 if ($clearUsers && !defined($group)) {
311 print "Please specify -group with -ClearUsers.\n\n";
315 if ($renameGroup && !defined($toGroup)) {
316 print "Please specify -to with -renamegroup.\n\n";
320 if ($assignDev && !defined($group)) {
321 print "Please specify -group with -assigndev.\n\n";
325 if ($replaceDev && (!defined($group) || !defined($devLun))) {
326 print "Please specify -group and -lun with -ReplaceDev.\n\n";
330 if ($releaseDev && !defined($group)) {
331 print "Please specify -group with -ReleaseDev.\n\n";
335 if ($clearDevs && !defined($group)) {
336 print "Please specify -group with -ClearDevs.\n\n";
340 if (defined($writeConfig) && !$writeConfig) {
341 print "Please specify a file name to write configuration to..\n\n";
345 $_DEBUG_ = $TRUE if (defined($_DEBUG_));
347 $forceConfig = $TRUE if (defined($forceConfig));
348 $showSessions = $TRUE if (defined($showSessions));
350 $enable =~ tr/A-Z/a-z/; $disable =~ tr/A-Z/a-z/;
351 $options =~ tr/a-z/A-Z/ if ($options);
353 if ((defined($showSessions) + defined($addDev) + defined($resyncDev) +
354 defined($removeDev)+ defined($addUser) + defined($enable) + defined($disable) +
355 defined($removeUser) + defined($clearUsers) + defined($assignDev) +
356 defined($releaseDev) + defined($clearDevs) + defined($applyConfig) +
357 defined($clearConfig) + defined($writeConfig) + defined($checkConfig)) > 1) {
358 print "Please specify only one operation at a time.\n";
362 $applyConfig = $_DEF_CONFIG_ if (defined($applyConfig) && !$applyConfig);
363 $checkConfig = $_DEF_CONFIG_ if (defined($checkConfig) && !$checkConfig);
365 return ($enable, $disable, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser,
366 $moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup,
367 $assignDev, $replaceDev, $releaseDev, $clearDevs, $handler, $group, $options, $blocksize,
368 $applyConfig, $forceConfig, $clearConfig, $writeConfig, $checkConfig, $showSessions);
374 STDOUT->autoflush(1);
376 # We need to run as root
377 if ( $> ) {die("This program must run as root.\n");}
379 my ($enable, $disable, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser,
380 $moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup,
381 $assignDev, $replaceDev, $releaseDev, $clearDevs, $handler, $group, $options, $blocksize,
382 $applyConfig, $forceConfig, $clearConfig, $writeConfig, $checkConfig, $showSessions) = getArgs();
384 $SCST = new SCST::SCST($_DEBUG_);
391 $rc = applyConfiguration($applyConfig, $TRUE, $TRUE);
392 die("Configuration errors found, aborting.\n") if ($rc);
394 print "\nConfiguration will apply in 10 seconds, type ctrl-c to abort..\n";
399 $rc = applyConfiguration($applyConfig, $forceConfig, $FALSE);
403 $rc = applyConfiguration($checkConfig, $FALSE, $TRUE);
407 $rc = writeConfiguration($writeConfig);
410 $showSessions && do {
411 $rc = showSessions();
414 defined($clearConfig) && do {
415 $rc = clearConfiguration();
419 $rc = addDevice($handler, $addDev, $devPath, $options, $blocksize);
423 $rc = resyncDevice($handler, $resyncDev);
427 $rc = removeDevice($handler, $removeDev);
431 $rc = addUser($group, $addUser);
435 $rc = moveUser($group, $moveUser, $toGroup);
439 $rc = removeUser($group, $removeUser);
442 defined($clearUsers) && do {
443 $rc = clearUsers($group);
447 $rc = addGroup($addGroup);
451 $rc = renameGroup($renameGroup, $toGroup);
455 $rc = removeGroup($removeGroup);
459 $rc = assignDevice($group, $assignDev, $devLun, $options);
463 $rc = replaceDevice($group, $replaceDev, $devLun, $options);
467 $rc = releaseDevice($group, $releaseDev);
470 defined($clearDevs) && do {
471 $rc = clearDevices($group);
475 $enable = unformatTarget($enable);
476 $rc = enableTarget($enable, $TRUE);
480 $disable = unformatTarget($disable);
481 $rc = enableTarget($disable, $FALSE);
485 print "No valid operations specified.\n";
495 sub readWorkingConfig {
498 print "Collecting current configuration.. ";
506 my $eHandlers = $SCST->handlers();
508 immediateExit($SCST->errorString());
510 foreach my $handler (@{$eHandlers}) {
511 $HANDLERS{$handler}++; # For quick lookups
514 $TARGETS = targets();
516 $DEVICES = $SCST->devices();
517 immediateExit($SCST->errorString());
519 my $_eGroups = $SCST->groups();
520 immediateExit($SCST->errorString());
522 foreach my $group (@{$_eGroups}) {
524 $ASSIGNMENTS{$group} = $SCST->groupDevices($group);
525 my $eUsers = $SCST->users($group);
527 foreach my $user (@{$eUsers}) {
528 $USERS{$group}->{$user}++; # For quick lookups
530 $USERS{$group} = \%empty if (!$USERS{$group});
536 sub writeConfiguration {
541 print "Failed to save current configuration, specified ".
542 "file exists and cannot be deleted.\n";
547 my $io = new IO::File $file, O_CREAT|O_WRONLY;
550 print "Failed to save configuration to file '$file': $!\n";
554 print "Writing current configuration to file '$file'.. ";
556 print $io "# Automatically generated by $Version.\n\n";
558 print $io "# NOTE: Options are pipe (|) seperated.\n\n";
561 foreach my $handler (sort keys %HANDLERS) {
562 if ($SCST->handlerType($handler) == $SCST::SCST::IOTYPE_VIRTUAL) {
563 print $io "[HANDLER ".$_REVERSE_MAP_{$handler}."]\n";
564 print $io "#DEVICE <vdisk name>,<device path>";
565 if ($handler == $SCST::SCST::VDISK_TYPE) {
566 print $io ",<options>,<block size>\n";
571 my $devices = $SCST->handlerDevices($handler);
573 immediateExit($SCST->errorString());
575 foreach my $device (sort keys %{$devices}) {
576 my $options = $$devices{$device}->{'OPTIONS'};
578 $options =~ s/\,/\|/g;
580 print $io "DEVICE $device,".$$devices{$device}->{'PATH'};
581 print $io ",$options";
582 print $io ",".$$devices{$device}->{'BLOCKSIZE'};
591 foreach my $group (sort keys %USERS) {
592 print $io "[GROUP $group]\n";
593 print $io "#USER <user wwn>\n";
595 foreach my $user (keys %{$USERS{$group}}) {
596 print $io "USER $user\n";
602 # Assignments configuration
603 foreach my $group (sort keys %ASSIGNMENTS) {
604 print $io "[ASSIGNMENT $group]\n";
605 print $io "#DEVICE <device name>,<lun>,<options>\n";
607 my $pointer = $ASSIGNMENTS{$group};
608 foreach my $device (sort keys %{$pointer}) {
609 print $io "DEVICE $device,".$$pointer{$device}."\n";
615 # Targets configuration
616 foreach my $type ('enable', 'disable') {
617 print $io "[TARGETS $type]\n";
618 print $io "#HOST <wwn identifier>\n";
620 foreach my $target (sort keys %{$TARGETS}) {
621 if ((($type eq 'enable') && $$TARGETS{$target}->{'enabled'}) ||
622 (($type eq 'disable') && !$$TARGETS{$target}->{'enabled'})) {
623 my $f_target = formatTarget($target);
624 print $io "HOST $f_target\n" if (!$$TARGETS{$target}->{'duplicate'});
638 sub applyConfiguration {
642 my $config = readConfig($confile);
648 my %used_assignments;
655 # Cache device/handler configuration
656 foreach my $entry (keys %{$$config{'HANDLER'}}) {
657 foreach my $device (@{$$config{'HANDLER'}->{$entry}->{'DEVICE'}}) {
658 my($vname, undef) = split(/\,/, $device, 2);
659 $vname = cleanupString($vname);
660 $used_devs{$vname} = $entry;
664 # Cache user/group configuration
665 foreach my $group (keys %{$$config{'GROUP'}}) {
666 foreach my $user (@{$$config{'GROUP'}->{$group}->{'USER'}}) {
667 if (defined($seen_users{$user})) {
668 print "\t-> FATAL: Configuration invalid. User '$user' is in more ".
672 $used_users{$group}->{$user}++;
673 $seen_users{$user}++;
675 $used_users{$group} = \%empty if (!$used_users{$group});
678 # Cache device association configuration
679 foreach my $group (keys %{$$config{'ASSIGNMENT'}}) {
680 foreach my $device (@{$$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
681 my($vname, $arg) = split(/\,/, $device, 2);
682 $vname = cleanupString($vname);
683 $used_assignments{$group}->{$vname} = $arg;
687 # If -ForceConfig is used, check for configurations which we've deleted but are still active.
688 if ($force || $check) {
690 foreach my $group (sort keys %ASSIGNMENTS) {
691 if (!defined($used_assignments{$group}) && (keys %{$ASSIGNMENTS{$group}})) {
692 print "\t-> WARNING: Group '$group' has no associations in saved configuration";
695 print ", clearing all associations.\n";
696 if (clearDevices($group)) {
706 my $_assignments = $ASSIGNMENTS{$group};
708 foreach my $device (sort keys %{$_assignments}) {
709 if (!defined($used_assignments{$group}->{$device}) ||
710 ($$_assignments{$device} != $used_assignments{$group}->{$device})) {
711 if (defined($used_assignments{$group}->{$device}) &&
712 ($$_assignments{$device} != $used_assignments{$group}->{$device})) {
713 print "\t-> WARNING: Device '$device' assigned to group '$group' ".
714 "is at LUN ".$used_assignments{$group}->{$device}.
715 " whereas working configuration reflects LUN ".$$_assignments{$device};
717 print "\t-> WARNING: Device '$device' is not associated with group ".
718 "'$group' in saved configuration";
722 my $_lun = $$_assignments{$device};
724 my $replace_dev = findAssignedLun($used_assignments{$group}, $_lun);
726 if (defined($replace_dev) && ($replace_dev ne $device)) {
727 print ", replacing with device '$replace_dev'.\n";
729 if (replaceDevice($group, $replace_dev, $_lun)) {
735 print ", releasing.\n";
736 if (releaseDevice($group, $device)) {
752 foreach my $group (sort keys %USERS) {
753 next if ($group eq $_DEFAULT_GROUP_);
754 if (!defined($used_users{$group})) {
755 print "\t-> WARNING: Group '$group' does not exist in saved configuration";
758 print ", removing.\n";
759 if (clearUsers($group)) {
765 if (removeGroup($group)) {
775 foreach my $user (sort keys %{$USERS{$group}}) {
776 if (!defined($used_users{$group}->{$user})) {
777 print "\t-> WARNING: User '$user' is not defined as part of group '$group' ".
778 "in saved configuration";
781 # Are we moving this user to another group?
782 my $new_group = findUserGroup($user, $config);
783 if ($new_group && ($new_group ne $group)) {
784 print ", moving to group '$new_group'.\n";
785 if (moveUser($group, $user, $new_group)) {
791 print ", removing.\n";
792 if (removeUser($group, $user)) {
808 foreach my $device (sort keys %{$DEVICES}) {
809 if ($$DEVICES{$device} && !defined($used_devs{$device})) {
810 # Device gone, but is it still assigned to a group?
811 my $isAssigned = $FALSE;
812 foreach my $group (sort keys %used_assignments) {
813 if (defined($used_assignments{$group}->{$device})) {
814 print "\t-> WARNING: Device '$device' is not defined in saved configuration, ".
815 "however, it is still assigned to group '$group'! Ignoring removal.\n";
820 if (!$isAssigned && ($SCST->handlerType($$DEVICES{$device}) == $SCST::SCST::IOTYPE_VIRTUAL)) {
821 print "\t-> WARNING: Device '$device' is not defined in saved configuration";
824 print ", removing.\n";
825 if (removeDevice($_REVERSE_MAP_{$$DEVICES{$device}}, $device)) {
837 if ($_HANDLER_MAP_{$used_devs{$device}} != $$DEVICES{$device}) {
838 my $handler = $used_devs{$device};
840 if ($HANDLERS{$_HANDLER_MAP_{$handler}}) {
841 print "\t-> WARNING: Device '$device' changes handler to '$handler'";
844 print ", changing.\n";
845 if ($SCST->assignDeviceToHandler($device,
846 $_HANDLER_MAP_{$handler})) {
861 print "Applying configuration additions..\n" if (!$check);
864 readWorkingConfig() if ($force);
866 foreach my $_handler (sort keys %{$$config{'HANDLER'}}) {
867 if (!$HANDLERS{$_HANDLER_MAP_{$_handler}}) {
868 print "\t-> WARNING: Handler '$_handler' does not exist.\n";
873 foreach my $device (@{$$config{'HANDLER'}->{$_handler}->{'DEVICE'}}) {
874 my($vname, $path, $options, $blocksize) = split(/\,/, $device);
875 $path = cleanupString($path);
876 $options =~ s/\s+//g;
878 if (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} == $$DEVICES{$vname})) {
880 } elsif (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} != $$DEVICES{$vname})) {
881 if ($HANDLERS{$_HANDLER_MAP_{$_handler}}) {
882 print "\t-> WARNING: Device '$vname' changes handler from '".
883 $_REVERSE_MAP_{$$DEVICES{$vname}}."' to '$_handler'.\n".
884 "\t Use -ForceConfig to change device handler.\n" if (!$force && !$check);
890 print "\t-> New device '$_handler:$vname' at path '$path', options '$options', ".
891 "blocksize $blocksize.\n";
892 $$DEVICES{$vname} = $_HANDLER_MAP_{$_handler};
895 if (addDevice($_handler, $vname, $path, $options, $blocksize)) {
904 # Create new groups and add users..
905 foreach my $group (keys %used_users) {
906 if (!defined($USERS{$group})) {
907 if ($group =~ /^$_TGT_DEF_PREFIX_/) {
908 my $rnd_id = randomGroupId();
909 my $tmp_group = $_TGT_TMP_PREFIX_.$rnd_id;
911 print "\t-> Using temporary group '$tmp_group' for group '$group'.\n";
913 $rename_group{$tmp_group} = $group;
914 $used_users{$tmp_group} = $used_users{$group};
919 print "\t-> New group definition '$group.'\n";
923 if (addGroup($group)) {
931 foreach my $user (keys %{$used_users{$group}}) {
932 if (!defined($USERS{$group}->{$user})) {
933 my $move_group = findUserGroupInCurrent($user);
935 print "\t-> WARNING: Use -ForceConfig to move user '$user' ".
936 "from group '$move_group' to group '$group'.\n" if (!$force);
941 print "\t-> New user definition '$user' for group '$group'.\n";
942 $USERS{$group}->{$user}++;
945 if (addUser($group, $user)) {
955 # Assign new devices to groups..
956 foreach my $group (keys %used_assignments) {
957 if (!defined($GROUPS{$group})) {
958 # Looks like we're lacking a group. We'll create an empty one
960 print "\t-> WARNING: Auto-creating an empty group '$group' since none was configured.\n";
962 if (addGroup($group)) {
969 if (!defined($GROUPS{$group})) {
970 print "\t-> WARNING: Unable to assign to non-existant group '$group'.\n";
975 foreach my $vname (keys %{$used_assignments{$group}}) {
976 my $arg = $used_assignments{$group}->{$vname};
977 my($lun, $options) = split(/\,/, $arg);
978 my $_assignments = $ASSIGNMENTS{$group};
980 if (defined($$_assignments{$vname}) && ($$_assignments{$vname} == $lun)) {
982 } elsif (defined($$_assignments{$vname}) && ($$_assignments{$vname} != $lun)) {
983 print "\t-> Device '$vname' assigned to group '$group' is at LUN ".$$_assignments{$vname}.
984 ", whereas the working configuration reflects LUN $lun.\n".
985 "\t Use -ForceConfig to force this LUN change.\n" if (!$force && !$check);
987 my $replace_dev = findAssignedLun($_assignments, $lun);
989 if (defined($replace_dev) && ($vname ne $replace_dev)) {
990 print "\t-> WARNING: Use -ForceConfig to replace device '$replace_dev' ".
991 "with device '$vname' for group '$group'.\n" if (!$force);
996 $lun = 'auto' if (!defined($lun));
997 print "\t-> New device assignment for '$vname' to group '$group' at LUN $lun.\n";
1000 if (assignDevice($group, $vname, $lun, $options)) {
1010 foreach my $tmp_group (keys %rename_group) {
1011 my $group = $rename_group{$tmp_group};
1012 print "\t-> Processing temporary group '$tmp_group'.\n";
1014 renameGroup($tmp_group, $group);
1017 # Enable/Disable configured targets
1018 foreach my $type (keys %{$$config{'TARGETS'}}) {
1021 if ($type eq 'enable') {
1023 } elsif ($type eq 'disable') {
1026 print "\t-> WARNING: Ignoring invalid TARGETS specifier '$type'. ".
1027 "Should be one of enable,disable.\n";
1031 foreach my $target (@{$$config{'TARGETS'}->{$type}->{'HOST'}}) {
1032 my $i_target = unformatTarget($target);
1034 if (!defined($$TARGETS{$i_target})) {
1035 print "\t-> WARNING: Target '$target' not found on system.\n";
1040 next if ($enable == targetEnabled($i_target));
1042 if (!$enable && targetEnabled($target)) {
1043 if ($force || $check) {
1044 print "\t-> WARNING: Target mode for '$target' is currently enabled, ".
1045 "however configuration file wants it disabled";
1048 print ", disabling.\n";
1049 if (enableTarget($target, $enable)) {
1060 print "\t-> Target '$target' is enabled in configuration file, ".
1061 "however is currently disabled";
1064 print ", enabling.\n";
1065 if (enableTarget($target, $enable)) {
1078 print "\nEncountered $errs error(s) while processing.\n" if ($errs);
1081 print "Configuration checked, $changes difference(s) found with working configuration.\n";
1083 $changes = 0 if ($_DEBUG_);
1084 print "Configuration applied, $changes changes made.\n";
1087 return $TRUE if ($errs);
1091 sub clearConfiguration {
1094 print "WARNING: This removes ALL applied SCST configuration and may result in data loss!\n";
1095 print "If this is not what you intend, press ctrl-c now. Waiting 10 seconds.\n\n";
1098 print "\nRemoving all users and groups:\n\n";
1099 foreach my $group (keys %GROUPS) {
1100 $errs += removeGroup($group) if ($group ne $_DEFAULT_GROUP_);
1103 print "\nRemoving all handler devices:\n\n";
1104 foreach my $device (keys %{$DEVICES}) {
1105 next if (!$$DEVICES{$device});
1106 next if ($SCST->handlerType($$DEVICES{$device}) != $SCST::SCST::IOTYPE_VIRTUAL);
1107 $errs += removeDevice($_REVERSE_MAP_{$$DEVICES{$device}}, $device);
1110 print "\nEncountered $errs error(s) while processing.\n" if ($errs);
1111 print "\nConfiguration cleared.\n";
1113 return $TRUE if ($errs);
1118 my $sessions = $SCST->sessions();
1119 immediateExit($SCST->errorString());
1121 print "\n\tTarget Name\tInitiator Name\t\t\tGroup Name\t\tCommand Count\n";
1123 foreach my $target (keys %{$sessions}) {
1124 foreach my $group (keys %{$$sessions{$target}}) {
1125 foreach my $user (keys %{$$sessions{$target}->{$group}}) {
1126 my $commands = $$sessions{$target}->{$group}->{$user};
1128 print "\t$target\t$user\t\t$group\t\t$commands\n";
1139 my $handler = shift;
1142 my $options = shift;
1143 my $blocksize = shift;
1145 my $_handler = $_HANDLER_MAP_{$handler};
1146 my $htype = $SCST->handlerType($_handler);
1149 print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
1153 if ($htype != $SCST::SCST::IOTYPE_VIRTUAL) {
1154 my $typeString = $_HANDLER_TYPE_MAP_{$htype};
1155 my $validType = $_HANDLER_TYPE_MAP_{$SCST::SCST::IOTYPE_VIRTUAL};
1156 print "WARNING: Handler $handler of type $typeString is incapable of ".
1157 "opening/closing devices. Valid handlers are:\n".
1158 validHandlerTypes($SCST::SCST::IOTYPE_VIRTUAL)."\n";
1162 if (defined($$DEVICES{$device})) {
1163 print "WARNING: Device '$device' already defined.\n";
1167 print "\t-> Opening virtual device '$device' at path '$path' using handler '$handler'..\n";
1169 if ($SCST->openDevice($_handler, $device, $path, $options, $blocksize)) {
1170 print "WARNING: Failed to open virtual device '$device' at path '$path': ".
1171 $SCST->errorString()."\n";
1175 $$DEVICES{$device} = $_handler;
1181 my $handler = shift;
1184 my $_handler = $_HANDLER_MAP_{$handler};
1185 my $htype = $SCST->handlerType($_handler);
1187 if (!defined($$DEVICES{$device})) {
1188 print "WARNING: Device '$device' not defined.\n";
1192 print "\t-> Resync'ing virtual device '$device'..\n";
1194 if ($SCST->resyncDevice($_handler, $device)) {
1195 print "WARNING: Failed to resync virtual device '$device': ".
1196 $SCST->errorString()."\n";
1204 my $handler = shift;
1207 my $_handler = $_HANDLER_MAP_{$handler};
1208 my $htype = $SCST->handlerType($_handler);
1211 print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
1215 if ($htype != $SCST::SCST::IOTYPE_VIRTUAL) {
1216 my $typeString = $_HANDLER_TYPE_MAP_{$htype};
1217 my $validType = $_HANDLER_TYPE_MAP_{$SCST::SCST::IOTYPE_VIRTUAL};
1218 print "WARNING: Handler $handler of type $typeString is incapable of ".
1219 "opening/closing devices. Valid handlers are:\n".
1220 validHandlerTypes($SCST::SCST::IOTYPE_VIRTUAL)."\n";
1224 if (!defined($$DEVICES{$device})) {
1225 print "WARNING: Device '$device' not defined.\n";
1229 print "\t-> Closing virtual device '$device'..\n";
1231 if ($SCST->closeDevice($_handler, $device)) {
1232 print "WARNING: Failed to close virtual device '$device': ".
1233 $SCST->errorString()."\n";
1237 undef $$DEVICES{$device};
1245 if (defined($GROUPS{$group})) {
1246 print "WARNING: Group '$group' already exists.\n";
1250 print "\t-> Creating security group '$group'..\n";
1252 if ($SCST->addGroup($group)) {
1253 print "WARNING: Failed to create security group '$group': ".
1254 $SCST->errorString()."\n";
1265 my $toGroup = shift;
1267 if (defined($GROUPS{$toGroup})) {
1268 print "WARNING: Group '$toGroup' already exists.\n";
1272 print "\t-> Renaming security group '$group' to '$toGroup'..\n";
1274 if ($SCST->renameGroup($group, $toGroup)) {
1275 print "WARNING: Failed to rename security group '$group' to ".
1276 "'$toGroup': ".$SCST->errorString()."\n";
1280 delete $GROUPS{$group};
1281 $GROUPS{$toGroup}++;
1289 return $FALSE if ($group eq $_DEFAULT_GROUP_);
1291 if (!defined($GROUPS{$group})) {
1292 print "WARNING: Group '$group' does not exist.\n";
1296 print "\t-> Removing security group '$group'..\n";
1298 if ($SCST->removeGroup($group)) {
1299 print "WARNING: Failed to remove security group '$group': ".
1300 $SCST->errorString()."\n";
1304 undef $GROUPS{$group};
1313 if (!defined($GROUPS{$group})) {
1314 print "WARNING: Failed to add user '$user' to group '$group', group does not exist.\n";
1318 if (defined($USERS{$group}->{$user})) {
1319 print "WARNING: User '$user' already exists in security group '$group'.\n";
1323 print "\t-> Adding user '$user' to security group '$group'..\n";
1325 if ($SCST->addUser($user, $group)) {
1326 print "WARNING: Failed to add user '$user' to security group '$group': ".
1327 $SCST->errorString()."\n";
1331 $USERS{$group}->{$user}++;
1339 my $toGroup = shift;
1341 if (!defined($GROUPS{$group})) {
1342 print "WARNING: Failed to move user '$user' from group '$group', group does not exist.\n";
1346 if (defined($USERS{$toGroup}->{$user})) {
1347 print "WARNING: User '$user' already exists in security group '$toGroup'.\n";
1351 print "\t-> Moving user '$user' from security group '$group' to security group '$toGroup'..\n";
1353 if ($SCST->moveUser($user, $group, $toGroup)) {
1354 print "WARNING: Failed to move user '$user' from security group '$group' to ".
1355 "security group '$toGroup': ".$SCST->errorString()."\n";
1359 delete $USERS{$group}->{$user};
1360 $USERS{$toGroup}->{$user}++;
1369 if (!defined($GROUPS{$group})) {
1370 print "WARNING: Failed to remove user '$user' from group '$group', group does not exist.\n";
1374 if (!defined($USERS{$group}->{$user})) {
1375 print "WARNING: User '$user' doesn\'t exist in security group '$group'.\n";
1379 print "\t-> Removing user '$user' from security group '$group'..\n";
1381 if ($SCST->removeUser($user, $group)) {
1382 print "WARNING: Failed to remove user '$user' to security group '$group': ".
1383 $SCST->errorString()."\n";
1387 undef $USERS{$group}->{$user};
1395 if (!defined($GROUPS{$group})) {
1396 print "WARNING: Failed to clear users from group '$group', group does not exist.\n";
1400 print "\t-> Clearing users from security group '$group'..\n";
1402 if ($SCST->clearUsers($group)) {
1403 print "WARNING: Failed to clear users from security group '$group': ".
1404 $SCST->errorString()."\n";
1408 undef $USERS{$group};
1417 my $options = shift;
1420 # Put luns into something easier to parse..
1421 foreach my $_group (keys %ASSIGNMENTS) {
1422 my $_gAssigns = $ASSIGNMENTS{$_group};
1424 foreach my $_device (keys %{$_gAssigns}) {
1425 @{$allLuns{$_group}}[$$_gAssigns{$_device}] = $_device;
1429 # Use the next available LUN if none specified
1430 if ($lun !~ /\d+/) {
1431 $lun = ($#{$allLuns{$group}} + 1);
1432 if ($lun > $_MAX_LUNS_) {
1433 print "ERROR: Unable to use next available LUN of $lun, lun out of range.\n";
1437 print "\t-> Device '$device': Using next available LUN of $lun for group '$group'.\n";
1440 if (($lun < 0) || ($lun > $_MAX_LUNS_)) {
1441 print "ERROR: Unable to assign device '$device', lun '$lun' is out of range.\n";
1445 if (!defined($$DEVICES{$device})) {
1446 print "WARNING: Unable to assign non-existant device '$device' to group '$group'.\n";
1450 if (@{$allLuns{$group}}[$lun]) {
1451 print "ERROR: Device '$device': Lun '$lun' is already assigned to device '".@{$allLuns{$group}}[$lun]."'.\n";
1455 print "\t-> Assign virtual device '$device' to group '$group' at LUN '$lun'..\n";
1457 if ($SCST->assignDeviceToGroup($device, $group, $lun, $options)) {
1458 print "WARNING: Failed to assign device '$device' to group '$group': ".
1459 $SCST->errorString()."\n";
1463 if (!defined($ASSIGNMENTS{$group})) {
1465 $ASSIGNMENTS{$group} = \%assignments_t;
1468 my $_assignments = $ASSIGNMENTS{$group};
1470 $$_assignments{$device} = $lun;
1477 my $newDevice = shift;
1479 my $options = shift;
1482 # Put luns into something easier to parse..
1483 foreach my $_group (keys %ASSIGNMENTS) {
1484 my $_gAssigns = $ASSIGNMENTS{$_group};
1486 foreach my $_device (keys %{$_gAssigns}) {
1487 @{$allLuns{$_group}}[$$_gAssigns{$_device}] = $_device;
1491 if (!defined($$DEVICES{$newDevice})) {
1492 print "WARNING: Unable to assign non-existant device '$newDevice' to group '$group'.\n";
1496 if (${$allLuns{$group}}[$lun] eq $newDevice) {
1497 print "ERROR: Device '$newDevice': Lun '$lun' is already assigned to device '$newDevice'.\n";
1501 print "\t-> Replace device at LUN '$lun' in group '$group' with new device '$newDevice'..\n";
1503 if ($SCST->replaceDeviceInGroup($newDevice, $group, $lun, $options)) {
1504 print "WARNING: Failed to replace LUN '$lun' in group '$group' with new device '$newDevice': ".
1505 $SCST->errorString()."\n";
1509 if (!defined($ASSIGNMENTS{$group})) {
1511 $ASSIGNMENTS{$group} = \%assignments_t;
1514 my $_assignments = $ASSIGNMENTS{$group};
1516 delete $$_assignments{${$allLuns{$group}}[$lun]};
1517 $$_assignments{$newDevice} = $lun;
1526 if (!defined($GROUPS{$group})) {
1527 print "WARNING: Failed to release device '$device' from group '$group', group does not exist.\n";
1531 if (!defined($$DEVICES{$device})) {
1532 print "WARNING: Failed to release device '$device', device not defined.\n";
1536 print "\t-> Release virtual device '$device' from group '$group'..\n";
1538 if ($SCST->removeDeviceFromGroup($device, $group)) {
1539 print "WARNING: Failed to release device '$device' from group '$group': ".
1540 $SCST->errorString()."\n";
1544 my $_assignments = $ASSIGNMENTS{$group};
1546 undef $$_assignments{$device};
1554 if (!defined($GROUPS{$group})) {
1555 print "WARNING: Failed to clear devices from group '$group', group does not exist.\n";
1559 print "\t-> Clear virtual devices from group '$group'..\n";
1561 if ($SCST->clearGroupDevices($group)) {
1562 print "WARNING: Failed to clear devices from group '$group': ".
1563 $SCST->errorString()."\n";
1567 undef $ASSIGNMENTS{$group};
1576 my $root = new IO::Dir $_FC_CLASS_ if (-d $_FC_CLASS_);
1579 while (my $entry = $root->read()) {
1580 next if (($entry eq '.') || ($entry eq '..'));
1582 my $io = new IO::File "$_FC_CLASS_/$entry/port_name", O_RDONLY;
1589 $fcards{$entry} = $wwn;
1594 $root = new IO::Dir $_SCSI_CLASS_ if (-d $_SCSI_CLASS_);
1597 while (my $entry = $root->read()) {
1598 next if (($entry eq '.') || ($entry eq '..'));
1600 my $io = new IO::File "$_SCSI_CLASS_/$entry/target_mode_enabled", O_RDONLY;
1603 my $enabled = <$io>;
1607 $targets{$entry}->{'path'} = "$_SCSI_CLASS_/$entry/target_mode_enabled";
1608 $targets{$entry}->{'enabled'} = $enabled;
1609 $targets{$entry}->{'qla_isp'} = $FALSE;
1611 if ($fcards{$entry}) {
1612 $targets{$fcards{$entry}}->{'enabled'} = $enabled;
1613 $targets{$fcards{$entry}}->{'path'} =
1614 "$_SCSI_CLASS_/$entry/target_mode_enabled";
1615 $targets{$entry}->{'duplicate'} = $TRUE;
1617 $targets{$entry}->{'duplicate'} = $FALSE;
1623 $root = new IO::Dir $_SCSI_ISP_ if (-d $_SCSI_ISP_);
1626 while (my $entry = $root->read()) {
1627 next if (($entry eq '.') || ($entry eq '..'));
1630 my $io = new IO::File "$_SCSI_ISP_/$entry", O_RDONLY;
1640 ($wwn) = ($fstr =~ '.*?Port WWN +([^\ ]+) .*');
1641 $fcards{$entry} = $wwn;
1643 $io = new IO::File "$_SCSITGT_QLAISP_/$entry", O_RDONLY;
1648 ($enabled2) = ($fstr =~ '[^\n]+\n *\d *: *(\d)');
1649 $targets{$entry}->{'path'} = "$_SCSITGT_QLAISP_/$entry";
1650 $targets{$entry}->{'enabled'} = $enabled2;
1651 $targets{$entry}->{'qla_isp'} = $TRUE;
1653 if ($fcards{$entry}) {
1654 $targets{$fcards{$entry}}->{'enabled'} = $enabled2;
1655 $targets{$fcards{$entry}}->{'path'} = "$_SCSITGT_QLAISP_/$entry";
1656 $targets{$fcards{$entry}}->{'qla_isp'} = $TRUE;
1657 $targets{$entry}->{'duplicate'} = $TRUE;
1659 $targets{$entry}->{'duplicate'} = $FALSE;
1672 return undef if (!defined($$TARGETS{$target}));
1673 return $$TARGETS{$target}->{'enabled'};
1680 $target = unformatTarget($target);
1682 return undef if (!defined($$TARGETS{$target}));
1684 my $io = new IO::File $$TARGETS{$target}->{'path'}, O_WRONLY;
1685 return $TRUE if (!$io);
1687 print $enable ? "\t-> Enabling" : "\t-> Disabling";
1688 print " target mode for SCST host '$target'.\n";
1691 print "DBG($$): ".$$TARGETS{$target}->{'path'}." -> $enable\n\n";
1693 if ($$TARGETS{$target}->{'qla_isp'} == $FALSE) {
1696 print $io $enable ? "enable all" : "disable all";
1702 $$TARGETS{$target}->{'enabled'} = $enable;
1708 my $confile = shift;
1716 my $io = new IO::File $confile, O_RDONLY;
1718 die("FATAL: Unable to open specified configuration file $confile: $!\n") if (!$io);
1720 while (my $line = <$io>) {
1721 ($line, undef) = split(/\#/, $line, 2);
1722 $line = cleanupString($line);
1724 if ($line =~ /^\[(.*)\]$/) {
1725 ($section, $arg) = split(/\s+/, $1, 2);
1727 if ($last_arg && ($last_arg ne $arg) &&
1728 !defined($config{$last_section}->{$last_arg})) {
1729 $config{$last_section}->{$last_arg} = \%empty;
1733 $last_section = $section;
1734 } elsif ($section && $arg && $line) {
1735 my($parameter, $value) = split(/\s+/, $line, 2);
1737 push @{$config{$section}->{$arg}->{$parameter}}, $value;
1750 foreach my $group (keys %{$$config{'GROUP'}}) {
1751 foreach my $_user (@{$$config{'GROUP'}->{$group}->{'USER'}}) {
1752 return $group if ($_user eq $user);
1759 sub findUserGroupInCurrent {
1762 foreach my $group (keys %USERS) {
1763 foreach my $_user (keys %{$USERS{$group}}) {
1764 return $group if ($_user eq $user);
1771 sub findAssignedLun {
1772 my $associations = shift;
1775 return undef if (!defined($lun));
1777 foreach my $device (keys %{$associations}) {
1778 if ($$associations{$device} == $lun) {
1789 $string =~ s/^\s+//;
1790 $string =~ s/\s+$//;
1798 if ($target =~ /^0x/) {
1800 my($o1, $o2, $o3, $o4, $o5, $o6, $o7, $o8) = unpack("A2A2A2A2A2A2A2A2", $target);
1801 $target = "$o1:$o2:$o3:$o4:$o5:$o6:$o7:$o8";
1804 $target =~ tr/A-Z/a-z/;
1809 sub unformatTarget {
1812 if ($target =~ /^.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}/) {
1814 $target = "0x$target";
1817 $target =~ tr/A-Z/a-z/;
1822 sub validHandlerTypes {
1826 foreach my $handler (keys %_REVERSE_MAP_) {
1827 $buffer .= "\t".$_REVERSE_MAP_{$handler}."\n" if ($SCST->handlerType($handler) == $type);
1834 return int(rand(10000));
1837 # If we have an unread error from SCST, exit immediately
1841 return if (!$error);
1843 print "\n\nFATAL: Received the following error:\n\n\t";
1851 print "\n\nAborting immediately.\n";