2 $Version = 'SCST Configurator v1.0.10';
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.
26 -issuelip : Issue LIP on all target-enabled FC fabrics.
29 -adddev <device> : Adds a device to a handler.
34 -resyncdev <device> : Resync the size of a device with the initiator(s).
36 -RemoveDev <device> : Remove a device from a handler.
40 -adduser <user> : Adds a user to a security group.
42 -MoveUser <user> : Moves a user from one security group to another.
45 -RemoveUser <user> : Delete a user from a security group.
47 -ClearUsers : Clear all users from a given security group.
51 -addgroup <group> : Add a given group to available security groups.
52 -renamegroup <group> : Renames a give group to a new name.
54 -RemoveGroup <group> : Remove a give group from available security groups.
57 -assigndev <device> : Assign a given device to a security group.
61 -ReplaceDev <new dev>: Replaces a device assigned to a give LUN and group.
65 -ReleaseDev <device> : Remove a given device from a security group.
67 -ClearDevs : Clear all device assignments for a security group.
71 -ForceConfig : Force all configuration changes, even deletions (DANGER!).
73 Debugging (limited support)
74 -debug : Debug mode - don\'t do anything destructive.
77 disk, vdisk, disk_perf, cdrom, vcdrom, changer, modisk, modisk_perf, tape, tape_perf
79 Available Options for create and open:
80 WRITE_THROUGH, READ_ONLY, O_DIRECT, NULLIO, NV_CACHE, BLOCK_IO, REMOVABLE
82 Available Options for assign and replace:
86 Enable target mode for fibre card specifying its WWN
87 scstadmin -enable 50:06:0B:00:00:39:71:78
89 Disable target mode for SCSI host specifying host number
90 scstadmin -disable host4
92 Create a new security group:
93 scstadmin -addgroup HOST01
95 Create a device given an already existing disk file:
96 scstadmin -adddev DISK01 -handler vdisk -path /vdisks/disk01.dsk -options READ_ONLY,WRITE_THROUGH
98 Assign a device to a security group:
99 scstadmin -assigndev DISK01 -group HOST01 -lun 1
101 Rename a security group:
102 scstadmin -RenameGroup HOST01 -to SERVER01
104 Tell all initiators to rescan LUNs:
117 my $_DEF_CONFIG_ = '/etc/scst.conf';
122 my $_MAX_LUNS_ = 255;
123 my $_DEFAULT_GROUP_ = 'Default';
125 my $_SCSI_CLASS_ = '/sys/class/scsi_host';
126 my $_FC_CLASS_ = '/sys/class/fc_host';
127 my $_SCSI_ISP_ = '/proc/scsi/isp';
128 my $_SCSITGT_QLAISP_ = '/proc/scsi_tgt/qla_isp';
130 my $_TGT_DEF_PREFIX_ = 'Default_';
131 my $_TGT_TMP_PREFIX_ = 'TMP_GRP';
142 my %_HANDLER_MAP_ = ('cdrom' => $SCST::SCST::CDROM_TYPE,
143 'changer' => $SCST::SCST::CHANGER_TYPE,
144 'disk' => $SCST::SCST::DISK_TYPE,
145 'vdisk' => $SCST::SCST::VDISK_TYPE,
146 'vcdrom' => $SCST::SCST::VCDROM_TYPE,
147 'disk_perf' => $SCST::SCST::DISKPERF_TYPE,
148 'modisk' => $SCST::SCST::MODISK_TYPE,
149 'modisk_perf' => $SCST::SCST::MODISKPERF_TYPE,
150 'tape' => $SCST::SCST::TAPE_TYPE,
151 'tape_perf' => $SCST::SCST::TAPEPERF_TYPE,
152 'processor' => $SCST::SCST::PROCESSOR_TYPE,
153 # Add in the dev_ names as well
154 'dev_cdrom' => $SCST::SCST::CDROM_TYPE,
155 'dev_changer' => $SCST::SCST::CHANGER_TYPE,
156 'dev_disk' => $SCST::SCST::DISK_TYPE,
157 'dev_disk_perf' => $SCST::SCST::DISKPERF_TYPE,
158 'dev_modisk' => $SCST::SCST::MODISK_TYPE,
159 'dev_modisk_perf' => $SCST::SCST::MODISKPERF_TYPE,
160 'dev_tape' => $SCST::SCST::TAPE_TYPE,
161 'dev_tape_perf' => $SCST::SCST::TAPEPERF_TYPE,
162 'dev_processor' => $SCST::SCST::PROCESSOR_TYPE);
164 my %_REVERSE_MAP_ = ($SCST::SCST::CDROM_TYPE => 'cdrom',
165 $SCST::SCST::CHANGER_TYPE => 'changer',
166 $SCST::SCST::DISK_TYPE => 'disk',
167 $SCST::SCST::VDISK_TYPE => 'vdisk',
168 $SCST::SCST::VCDROM_TYPE => 'vcdrom',
169 $SCST::SCST::DISKPERF_TYPE => 'disk_perf',
170 $SCST::SCST::MODISK_TYPE => 'modisk',
171 $SCST::SCST::MODISKPERF_TYPE => 'modisk_perf',
172 $SCST::SCST::TAPE_TYPE => 'tape',
173 $SCST::SCST::TAPEPERF_TYPE => 'tape_perf',
174 $SCST::SCST::PROCESSOR_TYPE => 'processor');
176 my %_HANDLER_TYPE_MAP_ = ($SCST::SCST::IOTYPE_PHYSICAL => 'physical',
177 $SCST::SCST::IOTYPE_VIRTUAL => 'virtual',
178 $SCST::SCST::IOTYPE_PERFORMANCE => 'performance');
180 $SIG{INT} = \&commitSuicide;
182 use vars qw($Version);
221 my $p = new Getopt::Long::Parser;
223 if (!$p->getoptions('config:s' => \$applyConfig,
224 'ClearConfig' => \$clearConfig,
225 'ForceConfig' => \$forceConfig,
226 'WriteConfig=s' => \$writeConfig,
227 'checkConfig=s' => \$checkConfig,
228 'sessions' => \$showSessions,
229 'adddev=s' => \$addDev,
230 'path=s' => \$devPath,
231 'ReplaceDev=s' => \$replaceDev,
232 'RemoveDev=s' => \$removeDev,
234 'adduser=s' => \$addUser,
235 'MoveUser=s' => \$moveUser,
236 'RemoveUser=s' => \$removeUser,
237 'ClearUsers' => \$clearUsers,
238 'addgroup=s' => \$addGroup,
240 'RemoveGroup=s' => \$removeGroup,
241 'renamegroup=s' => \$renameGroup,
242 'assigndev=s' => \$assignDev,
243 'resyncdev=s' => \$resyncDev,
244 'ReleaseDev=s' => \$releaseDev,
245 'ClearDevs' => \$clearDevs,
246 'handler=s' => \$handler,
247 'group=s' => \$group,
248 'options=s' => \$options,
249 'blocksize=s' => \$blocksize,
250 'enable=s' => \$enable,
251 'disable=s' => \$disable,
252 'issuelip' => \$issuelip,
253 'debug' => \$_DEBUG_)) {
257 if ((defined($enable) && !$enable) || (defined($disable) && !$disable)) {
258 print "Argument -enable/-disable requires a WWN or host.\n\n";
262 if (defined($issuelip) && ($enable || $disable)) {
263 print "Argument -issuelip cannot be used with -enable or -disable.\n\n";
267 if ($handler && !$_HANDLER_MAP_{$handler}) {
268 print "Invalid handler '$handler' specified. Available handlers are:\n\n";
269 foreach my $_handler (keys %_HANDLER_MAP_) {
270 print "\t$_handler\n";
276 if ($addDev && !($handler && $devPath)) {
277 print "Please specify -handler and -path with -adddev.\n\n";
281 if (defined($blocksize) && !$blocksize) {
282 print "Please specify bytes with -blocksize.\n\n";
286 if ($blocksize && !$addDev) {
287 print "Please specify -adddev with -blocksize.\n";
291 if (defined($forceConfig) && !defined($applyConfig)) {
292 print "Please specify -config with -ForceConfig.\n\n";
296 if ($resyncDev && !$handler) {
297 print "Please specify -handler with -resyncdev.\n\n";
301 if ($removeDev && !$handler) {
302 print "Please specify -handler with -RemoveDev.\n\n";
306 if ($addUser && !defined($group)) {
307 print "Please specify -group with -adduser.\n\n";
311 if ($moveUser && (!defined($group) || !defined($toGroup))) {
312 print "Please specify -group and -to with -MoveUser.\n\n";
316 if ($removeUser && !defined($group)) {
317 print "Please specify -group with -RemoveUser.\n\n";
321 if ($clearUsers && !defined($group)) {
322 print "Please specify -group with -ClearUsers.\n\n";
326 if ($renameGroup && !defined($toGroup)) {
327 print "Please specify -to with -renamegroup.\n\n";
331 if ($assignDev && !defined($group)) {
332 print "Please specify -group with -assigndev.\n\n";
336 if ($replaceDev && (!defined($group) || !defined($devLun))) {
337 print "Please specify -group and -lun with -ReplaceDev.\n\n";
341 if ($releaseDev && !defined($group)) {
342 print "Please specify -group with -ReleaseDev.\n\n";
346 if ($clearDevs && !defined($group)) {
347 print "Please specify -group with -ClearDevs.\n\n";
351 if (defined($writeConfig) && !$writeConfig) {
352 print "Please specify a file name to write configuration to..\n\n";
356 $_DEBUG_ = $TRUE if (defined($_DEBUG_));
358 $forceConfig = $TRUE if (defined($forceConfig));
359 $showSessions = $TRUE if (defined($showSessions));
360 $issuelip = $TRUE if (defined($issuelip));
362 $enable =~ tr/A-Z/a-z/; $disable =~ tr/A-Z/a-z/;
363 $options =~ tr/a-z/A-Z/ if ($options);
365 if ((defined($showSessions) + defined($addDev) + defined($resyncDev) +
366 defined($removeDev)+ defined($addUser) + defined($enable) + defined($disable) +
367 defined($removeUser) + defined($clearUsers) + defined($assignDev) +
368 defined($releaseDev) + defined($clearDevs) + defined($applyConfig) +
369 defined($clearConfig) + defined($writeConfig) + defined($checkConfig)) > 1) {
370 print "Please specify only one operation at a time.\n";
374 $applyConfig = $_DEF_CONFIG_ if (defined($applyConfig) && !$applyConfig);
375 $checkConfig = $_DEF_CONFIG_ if (defined($checkConfig) && !$checkConfig);
377 return ($enable, $disable, $issuelip, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser,
378 $moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup,
379 $assignDev, $replaceDev, $releaseDev, $clearDevs, $handler, $group, $options, $blocksize,
380 $applyConfig, $forceConfig, $clearConfig, $writeConfig, $checkConfig, $showSessions);
386 STDOUT->autoflush(1);
388 # We need to run as root
389 if ( $> ) {die("This program must run as root.\n");}
391 my ($enable, $disable, $issuelip, $addDev, $devPath, $devLun, $resyncDev, $removeDev, $addUser,
392 $moveUser, $removeUser, $clearUsers, $addGroup, $renameGroup, $toGroup, $removeGroup,
393 $assignDev, $replaceDev, $releaseDev, $clearDevs, $handler, $group, $options, $blocksize,
394 $applyConfig, $forceConfig, $clearConfig, $writeConfig, $checkConfig, $showSessions) = getArgs();
396 $SCST = new SCST::SCST($_DEBUG_);
403 $rc = applyConfiguration($applyConfig, $TRUE, $TRUE);
404 die("Configuration errors found, aborting.\n") if ($rc);
406 print "\nConfiguration will apply in 10 seconds, type ctrl-c to abort..\n";
411 $rc = applyConfiguration($applyConfig, $forceConfig, $FALSE);
415 $rc = applyConfiguration($checkConfig, $FALSE, $TRUE);
419 $rc = writeConfiguration($writeConfig);
422 $showSessions && do {
423 $rc = showSessions();
426 defined($clearConfig) && do {
427 $rc = clearConfiguration();
431 $rc = addDevice($handler, $addDev, $devPath, $options, $blocksize);
435 $rc = resyncDevice($handler, $resyncDev);
439 $rc = removeDevice($handler, $removeDev);
443 $rc = addUser($group, $addUser);
447 $rc = moveUser($group, $moveUser, $toGroup);
451 $rc = removeUser($group, $removeUser);
454 defined($clearUsers) && do {
455 $rc = clearUsers($group);
459 $rc = addGroup($addGroup);
463 $rc = renameGroup($renameGroup, $toGroup);
467 $rc = removeGroup($removeGroup);
471 $rc = assignDevice($group, $assignDev, $devLun, $options);
475 $rc = replaceDevice($group, $replaceDev, $devLun, $options);
479 $rc = releaseDevice($group, $releaseDev);
482 defined($clearDevs) && do {
483 $rc = clearDevices($group);
487 $enable = unformatTarget($enable);
488 $rc = enableTarget($enable, $TRUE);
492 $disable = unformatTarget($disable);
493 $rc = enableTarget($disable, $FALSE);
501 print "No valid operations specified.\n";
506 print "\nAll done.\n";
511 sub readWorkingConfig {
514 print "Collecting current configuration: ";
522 my $eHandlers = $SCST->handlers();
524 immediateExit($SCST->errorString());
526 foreach my $handler (@{$eHandlers}) {
527 $HANDLERS{$handler}++; # For quick lookups
530 $TARGETS = targets();
532 $DEVICES = $SCST->devices();
533 immediateExit($SCST->errorString());
535 my $_eGroups = $SCST->groups();
536 immediateExit($SCST->errorString());
538 foreach my $group (@{$_eGroups}) {
540 $ASSIGNMENTS{$group} = $SCST->groupDevices($group);
541 my $eUsers = $SCST->users($group);
543 foreach my $user (@{$eUsers}) {
544 $USERS{$group}->{$user}++; # For quick lookups
546 $USERS{$group} = \%empty if (!$USERS{$group});
552 sub writeConfiguration {
556 my $config = readConfig($file, $TRUE);
560 print "Failed to save current configuration, specified ".
561 "file exists and cannot be deleted.\n";
566 my $io = new IO::File $file, O_CREAT|O_WRONLY;
569 print "Failed to save configuration to file '$file': $!\n";
573 print "Writing current configuration to file '$file'.. ";
575 print $io "# Automatically generated by $Version.\n\n";
577 print $io "# NOTE: Options are pipe (|) seperated.\n\n";
579 print $io "[OPTIONS]\n";
580 print $io "#OPTION <1|0|YES|NO|TRUE|FALSE|VALUE>\n";
581 print $io "# Copy configuration options during a -writeconfig\n";
582 print $io "KEEP_CONFIG ";
584 if (defined($config)) {
585 $keep_config = $$config{'OPTIONS'}->{'default'}->{'KEEP_CONFIG'}[0];
587 $keep_config = $FALSE;
590 if (!defined($config)) {
592 } elsif (!$keep_config ) {
598 print $io "# For FC targets, issue a LIP after every assignment change\n";
599 print $io "ISSUE_LIP ";
604 print $io ($$config{'OPTIONS'}->{'default'}->{'ISSUE_LIP'}[0] ? "TRUE\n" : "FALSE\n");
610 foreach my $handler (sort keys %HANDLERS) {
611 if ($SCST->handlerType($handler) == $SCST::SCST::IOTYPE_VIRTUAL) {
612 print $io "[HANDLER ".$_REVERSE_MAP_{$handler}."]\n";
613 print $io "#DEVICE <vdisk name>,<device path>";
614 if ($handler == $SCST::SCST::VDISK_TYPE) {
615 print $io ",<options>,<block size>\n";
620 my $devices = $SCST->handlerDevices($handler);
622 immediateExit($SCST->errorString());
624 foreach my $device (sort keys %{$devices}) {
625 my $options = $$devices{$device}->{'OPTIONS'};
627 $options =~ s/\,/\|/g;
629 print $io "DEVICE $device,".$$devices{$device}->{'PATH'};
630 print $io ",$options";
631 print $io ",".$$devices{$device}->{'BLOCKSIZE'};
640 foreach my $group (sort keys %USERS) {
641 print $io "[GROUP $group]\n";
642 print $io "#USER <user wwn>\n";
644 foreach my $user (keys %{$USERS{$group}}) {
645 print $io "USER $user\n";
651 # Assignments configuration
652 foreach my $group (sort keys %ASSIGNMENTS) {
653 print $io "[ASSIGNMENT $group]\n";
654 print $io "#DEVICE <device name>,<lun>,<options>\n";
656 my $pointer = $ASSIGNMENTS{$group};
657 foreach my $device (sort keys %{$pointer}) {
658 print $io "DEVICE $device,".$$pointer{$device}."\n";
664 # Targets configuration
665 foreach my $type ('enable', 'disable') {
666 print $io "[TARGETS $type]\n";
667 print $io "#HOST <wwn identifier>\n";
669 foreach my $target (sort keys %{$TARGETS}) {
670 if ((($type eq 'enable') && $$TARGETS{$target}->{'enabled'}) ||
671 (($type eq 'disable') && !$$TARGETS{$target}->{'enabled'})) {
672 my $f_target = formatTarget($target);
673 print $io "HOST $f_target\n" if (!$$TARGETS{$target}->{'duplicate'});
687 sub applyConfiguration {
691 my $config = readConfig($confile);
695 my $assign_changes = 0;
696 my $targets_changed = $FALSE;
700 my %used_assignments;
707 my $issue_lip = $$config{'OPTIONS'}->{'default'}->{'ISSUE_LIP'}[0];
709 # Cache device/handler configuration
710 foreach my $entry (keys %{$$config{'HANDLER'}}) {
711 foreach my $device (@{$$config{'HANDLER'}->{$entry}->{'DEVICE'}}) {
712 my($vname, undef) = split(/\,/, $device, 2);
713 $vname = cleanupString($vname);
714 $used_devs{$vname} = $entry;
718 # Cache user/group configuration
719 foreach my $group (keys %{$$config{'GROUP'}}) {
720 foreach my $user (@{$$config{'GROUP'}->{$group}->{'USER'}}) {
721 if (defined($seen_users{$user})) {
722 print "\t-> FATAL: Configuration invalid. User '$user' is in more ".
726 $used_users{$group}->{$user}++;
727 $seen_users{$user}++;
729 $used_users{$group} = \%empty if (!$used_users{$group});
732 # Cache device association configuration
733 foreach my $group (keys %{$$config{'ASSIGNMENT'}}) {
736 foreach my $device (@{$$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
737 my($vname, $arg) = split(/\,/, $device, 2);
738 $vname = cleanupString($vname);
739 my($lun, $options) = split(/\,/, $arg);
740 if ($seen_luns{$lun}) {
741 print "\t-> FATAL: Configuration invalid. Group '$group' has multiple ".
742 "devices assigned to LUN $lun.\n";
745 $used_assignments{$group}->{$vname} = $arg;
750 # If -ForceConfig is used, check for configurations which we've deleted but are still active.
751 if ($force || $check) {
753 foreach my $group (sort keys %ASSIGNMENTS) {
754 if (!defined($used_assignments{$group}) && (keys %{$ASSIGNMENTS{$group}})) {
755 print "\t-> WARNING: Group '$group' has no associations in saved configuration";
758 print ", clearing all associations.\n";
759 if (clearDevices($group)) {
770 my $_assignments = $ASSIGNMENTS{$group};
772 foreach my $device (sort keys %{$_assignments}) {
773 if (!defined($used_assignments{$group}->{$device}) ||
774 ($$_assignments{$device} != $used_assignments{$group}->{$device})) {
775 if (defined($used_assignments{$group}->{$device}) &&
776 ($$_assignments{$device} != $used_assignments{$group}->{$device})) {
777 print "\t-> WARNING: Device '$device' assigned to group '$group' ".
778 "is at LUN ".$used_assignments{$group}->{$device}.
779 " whereas working configuration reflects LUN ".$$_assignments{$device};
781 print "\t-> WARNING: Device '$device' is not associated with group ".
782 "'$group' in saved configuration";
786 my $_lun = $$_assignments{$device};
787 my $replace_dev = findAssignedLun($used_assignments{$group}, $_lun);
789 if (defined($replace_dev) && ($replace_dev ne $device)) {
790 print ", replacing with device '$replace_dev'.\n";
792 if (replaceDevice($group, $replace_dev, $_lun)) {
799 print ", releasing.\n";
800 if (releaseDevice($group, $device)) {
817 foreach my $group (sort keys %USERS) {
818 next if ($group eq $_DEFAULT_GROUP_);
819 if (!defined($used_users{$group})) {
820 print "\t-> WARNING: Group '$group' does not exist in saved configuration";
823 print ", removing.\n";
824 if (clearUsers($group)) {
830 if (removeGroup($group)) {
840 foreach my $user (sort keys %{$USERS{$group}}) {
841 if (!defined($used_users{$group}->{$user})) {
842 print "\t-> WARNING: User '$user' is not defined as part of group '$group' ".
843 "in saved configuration";
846 # Are we moving this user to another group?
847 my $new_group = findUserGroup($user, $config);
848 if ($new_group && ($new_group ne $group)) {
849 print ", moving to group '$new_group'.\n";
850 if (moveUser($group, $user, $new_group)) {
856 print ", removing.\n";
857 if (removeUser($group, $user)) {
873 foreach my $device (sort keys %{$DEVICES}) {
874 if ($$DEVICES{$device} && !defined($used_devs{$device})) {
875 # Device gone, but is it still assigned to a group?
876 my $isAssigned = $FALSE;
877 foreach my $group (sort keys %used_assignments) {
878 if (defined($used_assignments{$group}->{$device})) {
879 print "\t-> WARNING: Device '$device' is not defined in saved configuration, ".
880 "however, it is still assigned to group '$group'! Ignoring removal.\n";
885 if (!$isAssigned && ($SCST->handlerType($$DEVICES{$device}) == $SCST::SCST::IOTYPE_VIRTUAL)) {
886 print "\t-> WARNING: Device '$device' is not defined in saved configuration";
889 print ", removing.\n";
890 if (removeDevice($_REVERSE_MAP_{$$DEVICES{$device}}, $device)) {
902 if ($_HANDLER_MAP_{$used_devs{$device}} != $$DEVICES{$device}) {
903 my $handler = $used_devs{$device};
905 if ($HANDLERS{$_HANDLER_MAP_{$handler}}) {
906 print "\t-> WARNING: Device '$device' changes handler to '$handler'";
909 print ", changing.\n";
910 if ($SCST->assignDeviceToHandler($device,
911 $_HANDLER_MAP_{$handler})) {
926 print "\nApplying configuration additions..\n" if (!$check);
929 readWorkingConfig() if ($force);
931 foreach my $_handler (sort keys %{$$config{'HANDLER'}}) {
932 if (!$HANDLERS{$_HANDLER_MAP_{$_handler}}) {
933 print "\t-> WARNING: Handler '$_handler' does not exist.\n";
938 foreach my $device (@{$$config{'HANDLER'}->{$_handler}->{'DEVICE'}}) {
939 my($vname, $path, $options, $blocksize) = split(/\,/, $device);
940 $path = cleanupString($path);
941 $options =~ s/\s+//g;
943 if (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} == $$DEVICES{$vname})) {
945 } elsif (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} != $$DEVICES{$vname})) {
946 if ($HANDLERS{$_HANDLER_MAP_{$_handler}}) {
947 print "\t-> WARNING: Device '$vname' changes handler from '".
948 $_REVERSE_MAP_{$$DEVICES{$vname}}."' to '$_handler'.\n".
949 "\t Use -ForceConfig to change device handler.\n" if (!$force && !$check);
955 print "\t-> New device '$_handler:$vname' at path '$path', options '$options', ".
956 "blocksize $blocksize.\n";
957 $$DEVICES{$vname} = $_HANDLER_MAP_{$_handler};
960 if (addDevice($_handler, $vname, $path, $options, $blocksize)) {
969 # Create new groups and add users..
970 foreach my $group (keys %used_users) {
971 if (!defined($USERS{$group})) {
972 if ($group =~ /^$_TGT_DEF_PREFIX_/) {
973 my $rnd_id = randomGroupId();
974 my $tmp_group = $_TGT_TMP_PREFIX_.$rnd_id;
976 print "\t-> Using temporary group '$tmp_group' for group '$group'.\n";
978 $rename_group{$tmp_group} = $group;
979 $used_users{$tmp_group} = $used_users{$group};
984 print "\t-> New group definition '$group.'\n";
988 if (addGroup($group)) {
996 foreach my $user (keys %{$used_users{$group}}) {
997 if (!defined($USERS{$group}->{$user})) {
998 my $move_group = findUserGroupInCurrent($user);
1000 print "\t-> WARNING: Use -ForceConfig to move user '$user' ".
1001 "from group '$move_group' to group '$group'.\n" if (!$force);
1006 print "\t-> New user definition '$user' for group '$group'.\n";
1007 $USERS{$group}->{$user}++;
1010 if (addUser($group, $user)) {
1020 # Assign new devices to groups..
1021 foreach my $group (keys %used_assignments) {
1022 if (!defined($GROUPS{$group})) {
1023 # Looks like we're lacking a group. We'll create an empty one
1025 print "\t-> WARNING: Auto-creating an empty group '$group' since none was configured.\n";
1027 if (addGroup($group)) {
1034 if (!defined($GROUPS{$group})) {
1035 print "\t-> WARNING: Unable to assign to non-existant group '$group'.\n";
1040 foreach my $vname (keys %{$used_assignments{$group}}) {
1041 my $arg = $used_assignments{$group}->{$vname};
1042 my($lun, $options) = split(/\,/, $arg);
1043 my $_assignments = $ASSIGNMENTS{$group};
1045 if (defined($$_assignments{$vname}) && ($$_assignments{$vname} == $lun)) {
1047 } elsif (defined($$_assignments{$vname}) && ($$_assignments{$vname} != $lun)) {
1048 print "\t-> Device '$vname' assigned to group '$group' is at LUN ".$$_assignments{$vname}.
1049 ", whereas the working configuration reflects LUN $lun.\n".
1050 "\t Use -ForceConfig to force this LUN change.\n" if (!$force && !$check);
1052 my $replace_dev = findAssignedLun($_assignments, $lun);
1054 if (defined($replace_dev) && ($vname ne $replace_dev)) {
1055 print "\t-> WARNING: Use -ForceConfig to replace device '$replace_dev' ".
1056 "with device '$vname' for group '$group'.\n" if (!$force);
1061 $lun = 'auto' if (!defined($lun));
1062 print "\t-> New device assignment for '$vname' to group '$group' at LUN $lun.\n";
1065 if (assignDevice($group, $vname, $lun, $options)) {
1076 foreach my $tmp_group (keys %rename_group) {
1077 my $group = $rename_group{$tmp_group};
1078 print "\t-> Processing temporary group '$tmp_group'.\n";
1080 renameGroup($tmp_group, $group);
1083 # Enable/Disable configured targets
1084 foreach my $type (keys %{$$config{'TARGETS'}}) {
1087 if ($type eq 'enable') {
1089 } elsif ($type eq 'disable') {
1092 print "\t-> WARNING: Ignoring invalid TARGETS specifier '$type'. ".
1093 "Should be one of enable, disable.\n";
1097 foreach my $target (@{$$config{'TARGETS'}->{$type}->{'HOST'}}) {
1098 my $i_target = unformatTarget($target);
1100 if (!defined($$TARGETS{$i_target})) {
1101 print "\t-> WARNING: Target '$target' not found on system.\n";
1106 next if ($enable == targetEnabled($i_target));
1108 if (!$enable && targetEnabled($target)) {
1109 if ($force || $check) {
1110 print "\t-> WARNING: Target mode for '$target' is currently enabled, ".
1111 "however configuration file wants it disabled";
1114 print ", disabling.\n";
1115 if (enableTarget($target, $enable)) {
1119 $targets_changed = $TRUE;
1127 print "\t-> Target '$target' is enabled in configuration file, ".
1128 "however is currently disabled";
1131 print ", enabling.\n";
1132 if (enableTarget($target, $enable)) {
1136 $targets_changed = $TRUE;
1146 if ($issue_lip && $assign_changes && !$targets_changed) {
1147 print "\nMaking initiators aware of assignment changes..\n\n";
1151 print "\n\nEncountered $errs error(s) while processing.\n" if ($errs);
1154 print "\nConfiguration checked, $changes difference(s) found with working configuration.\n";
1156 $changes = 0 if ($_DEBUG_);
1157 print "\nConfiguration applied, $changes changes made.\n";
1160 return $TRUE if ($errs);
1164 sub clearConfiguration {
1167 print "WARNING: This removes ALL applied SCST configuration and may result in data loss!\n";
1168 print "If this is not what you intend, press ctrl-c now. Waiting 10 seconds.\n\n";
1171 print "\nRemoving all users and groups:\n\n";
1172 foreach my $group (keys %GROUPS) {
1173 $errs += removeGroup($group) if ($group ne $_DEFAULT_GROUP_);
1176 print "\nRemoving all handler devices:\n\n";
1177 foreach my $device (keys %{$DEVICES}) {
1178 next if (!$$DEVICES{$device});
1179 next if ($SCST->handlerType($$DEVICES{$device}) != $SCST::SCST::IOTYPE_VIRTUAL);
1180 $errs += removeDevice($_REVERSE_MAP_{$$DEVICES{$device}}, $device);
1183 print "\nEncountered $errs error(s) while processing.\n" if ($errs);
1184 print "\nConfiguration cleared.\n";
1186 return $TRUE if ($errs);
1191 my $sessions = $SCST->sessions();
1192 immediateExit($SCST->errorString());
1194 print "\n\tTarget Name\tInitiator Name\t\t\tGroup Name\t\tCommand Count\n";
1196 foreach my $target (keys %{$sessions}) {
1197 foreach my $group (keys %{$$sessions{$target}}) {
1198 foreach my $user (keys %{$$sessions{$target}->{$group}}) {
1199 my $commands = $$sessions{$target}->{$group}->{$user};
1201 print "\t$target\t$user\t\t$group\t\t$commands\n";
1212 my $handler = shift;
1215 my $options = shift;
1216 my $blocksize = shift;
1218 my $_handler = $_HANDLER_MAP_{$handler};
1219 my $htype = $SCST->handlerType($_handler);
1222 print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
1226 if ($htype != $SCST::SCST::IOTYPE_VIRTUAL) {
1227 my $typeString = $_HANDLER_TYPE_MAP_{$htype};
1228 my $validType = $_HANDLER_TYPE_MAP_{$SCST::SCST::IOTYPE_VIRTUAL};
1229 print "WARNING: Handler $handler of type $typeString is incapable of ".
1230 "opening/closing devices. Valid handlers are:\n".
1231 validHandlerTypes($SCST::SCST::IOTYPE_VIRTUAL)."\n";
1235 if (defined($$DEVICES{$device})) {
1236 print "WARNING: Device '$device' already defined.\n";
1240 print "\t-> Opening virtual device '$device' at path '$path' using handler '$handler'..\n";
1242 if ($SCST->openDevice($_handler, $device, $path, $options, $blocksize)) {
1243 print "WARNING: Failed to open virtual device '$device' at path '$path': ".
1244 $SCST->errorString()."\n";
1248 $$DEVICES{$device} = $_handler;
1254 my $handler = shift;
1257 my $_handler = $_HANDLER_MAP_{$handler};
1258 my $htype = $SCST->handlerType($_handler);
1260 if (!defined($$DEVICES{$device})) {
1261 print "WARNING: Device '$device' not defined.\n";
1265 print "\t-> Resync'ing virtual device '$device'..\n";
1267 if ($SCST->resyncDevice($_handler, $device)) {
1268 print "WARNING: Failed to resync virtual device '$device': ".
1269 $SCST->errorString()."\n";
1277 my $handler = shift;
1280 my $_handler = $_HANDLER_MAP_{$handler};
1281 my $htype = $SCST->handlerType($_handler);
1284 print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
1288 if ($htype != $SCST::SCST::IOTYPE_VIRTUAL) {
1289 my $typeString = $_HANDLER_TYPE_MAP_{$htype};
1290 my $validType = $_HANDLER_TYPE_MAP_{$SCST::SCST::IOTYPE_VIRTUAL};
1291 print "WARNING: Handler $handler of type $typeString is incapable of ".
1292 "opening/closing devices. Valid handlers are:\n".
1293 validHandlerTypes($SCST::SCST::IOTYPE_VIRTUAL)."\n";
1297 if (!defined($$DEVICES{$device})) {
1298 print "WARNING: Device '$device' not defined.\n";
1302 print "\t-> Closing virtual device '$device'..\n";
1304 if ($SCST->closeDevice($_handler, $device)) {
1305 print "WARNING: Failed to close virtual device '$device': ".
1306 $SCST->errorString()."\n";
1310 undef $$DEVICES{$device};
1318 if (defined($GROUPS{$group})) {
1319 print "WARNING: Group '$group' already exists.\n";
1323 print "\t-> Creating security group '$group'..\n";
1325 if ($SCST->addGroup($group)) {
1326 print "WARNING: Failed to create security group '$group': ".
1327 $SCST->errorString()."\n";
1338 my $toGroup = shift;
1340 if (defined($GROUPS{$toGroup})) {
1341 print "WARNING: Group '$toGroup' already exists.\n";
1345 print "\t-> Renaming security group '$group' to '$toGroup'..\n";
1347 if ($SCST->renameGroup($group, $toGroup)) {
1348 print "WARNING: Failed to rename security group '$group' to ".
1349 "'$toGroup': ".$SCST->errorString()."\n";
1353 delete $GROUPS{$group};
1354 $GROUPS{$toGroup}++;
1362 return $FALSE if ($group eq $_DEFAULT_GROUP_);
1364 if (!defined($GROUPS{$group})) {
1365 print "WARNING: Group '$group' does not exist.\n";
1369 print "\t-> Removing security group '$group'..\n";
1371 if ($SCST->removeGroup($group)) {
1372 print "WARNING: Failed to remove security group '$group': ".
1373 $SCST->errorString()."\n";
1377 undef $GROUPS{$group};
1386 if (!defined($GROUPS{$group})) {
1387 print "WARNING: Failed to add user '$user' to group '$group', group does not exist.\n";
1391 if (defined($USERS{$group}->{$user})) {
1392 print "WARNING: User '$user' already exists in security group '$group'.\n";
1396 print "\t-> Adding user '$user' to security group '$group'..\n";
1398 if ($SCST->addUser($user, $group)) {
1399 print "WARNING: Failed to add user '$user' to security group '$group': ".
1400 $SCST->errorString()."\n";
1404 $USERS{$group}->{$user}++;
1412 my $toGroup = shift;
1414 if (!defined($GROUPS{$group})) {
1415 print "WARNING: Failed to move user '$user' from group '$group', group does not exist.\n";
1419 if (defined($USERS{$toGroup}->{$user})) {
1420 print "WARNING: User '$user' already exists in security group '$toGroup'.\n";
1424 print "\t-> Moving user '$user' from security group '$group' to security group '$toGroup'..\n";
1426 if ($SCST->moveUser($user, $group, $toGroup)) {
1427 print "WARNING: Failed to move user '$user' from security group '$group' to ".
1428 "security group '$toGroup': ".$SCST->errorString()."\n";
1432 delete $USERS{$group}->{$user};
1433 $USERS{$toGroup}->{$user}++;
1442 if (!defined($GROUPS{$group})) {
1443 print "WARNING: Failed to remove user '$user' from group '$group', group does not exist.\n";
1447 if (!defined($USERS{$group}->{$user})) {
1448 print "WARNING: User '$user' doesn\'t exist in security group '$group'.\n";
1452 print "\t-> Removing user '$user' from security group '$group'..\n";
1454 if ($SCST->removeUser($user, $group)) {
1455 print "WARNING: Failed to remove user '$user' to security group '$group': ".
1456 $SCST->errorString()."\n";
1460 undef $USERS{$group}->{$user};
1468 if (!defined($GROUPS{$group})) {
1469 print "WARNING: Failed to clear users from group '$group', group does not exist.\n";
1473 print "\t-> Clearing users from security group '$group'..\n";
1475 if ($SCST->clearUsers($group)) {
1476 print "WARNING: Failed to clear users from security group '$group': ".
1477 $SCST->errorString()."\n";
1481 undef $USERS{$group};
1490 my $options = shift;
1493 # Put luns into something easier to parse..
1494 foreach my $_group (keys %ASSIGNMENTS) {
1495 my $_gAssigns = $ASSIGNMENTS{$_group};
1497 foreach my $_device (keys %{$_gAssigns}) {
1498 @{$allLuns{$_group}}[$$_gAssigns{$_device}] = $_device;
1502 # Use the next available LUN if none specified
1503 if ($lun !~ /\d+/) {
1504 $lun = ($#{$allLuns{$group}} + 1);
1505 if ($lun > $_MAX_LUNS_) {
1506 print "ERROR: Unable to use next available LUN of $lun, lun out of range.\n";
1510 print "\t-> Device '$device': Using next available LUN of $lun for group '$group'.\n";
1513 if (($lun < 0) || ($lun > $_MAX_LUNS_)) {
1514 print "ERROR: Unable to assign device '$device', lun '$lun' is out of range.\n";
1518 if (!defined($$DEVICES{$device})) {
1519 print "WARNING: Unable to assign non-existant device '$device' to group '$group'.\n";
1523 if (@{$allLuns{$group}}[$lun]) {
1524 print "ERROR: Device '$device': Lun '$lun' is already assigned to device '".@{$allLuns{$group}}[$lun]."'.\n";
1528 print "\t-> Assign virtual device '$device' to group '$group' at LUN '$lun'..\n";
1530 if ($SCST->assignDeviceToGroup($device, $group, $lun, $options)) {
1531 print "WARNING: Failed to assign device '$device' to group '$group': ".
1532 $SCST->errorString()."\n";
1536 if (!defined($ASSIGNMENTS{$group})) {
1538 $ASSIGNMENTS{$group} = \%assignments_t;
1541 my $_assignments = $ASSIGNMENTS{$group};
1543 $$_assignments{$device} = $lun;
1550 my $newDevice = shift;
1552 my $options = shift;
1555 # Put luns into something easier to parse..
1556 foreach my $_group (keys %ASSIGNMENTS) {
1557 my $_gAssigns = $ASSIGNMENTS{$_group};
1559 foreach my $_device (keys %{$_gAssigns}) {
1560 @{$allLuns{$_group}}[$$_gAssigns{$_device}] = $_device;
1564 if (!defined($$DEVICES{$newDevice})) {
1565 print "WARNING: Unable to assign non-existant device '$newDevice' to group '$group'.\n";
1569 if (${$allLuns{$group}}[$lun] eq $newDevice) {
1570 print "ERROR: Device '$newDevice': Lun '$lun' is already assigned to device '$newDevice'.\n";
1574 print "\t-> Replace device at LUN '$lun' in group '$group' with new device '$newDevice'..\n";
1576 if ($SCST->replaceDeviceInGroup($newDevice, $group, $lun, $options)) {
1577 print "WARNING: Failed to replace LUN '$lun' in group '$group' with new device '$newDevice': ".
1578 $SCST->errorString()."\n";
1582 if (!defined($ASSIGNMENTS{$group})) {
1584 $ASSIGNMENTS{$group} = \%assignments_t;
1587 my $_assignments = $ASSIGNMENTS{$group};
1589 delete $$_assignments{${$allLuns{$group}}[$lun]};
1590 $$_assignments{$newDevice} = $lun;
1599 if (!defined($GROUPS{$group})) {
1600 print "WARNING: Failed to release device '$device' from group '$group', group does not exist.\n";
1604 if (!defined($$DEVICES{$device})) {
1605 print "WARNING: Failed to release device '$device', device not defined.\n";
1609 print "\t-> Release virtual device '$device' from group '$group'..\n";
1611 if ($SCST->removeDeviceFromGroup($device, $group)) {
1612 print "WARNING: Failed to release device '$device' from group '$group': ".
1613 $SCST->errorString()."\n";
1617 my $_assignments = $ASSIGNMENTS{$group};
1619 undef $$_assignments{$device};
1627 if (!defined($GROUPS{$group})) {
1628 print "WARNING: Failed to clear devices from group '$group', group does not exist.\n";
1632 print "\t-> Clear virtual devices from group '$group'..\n";
1634 if ($SCST->clearGroupDevices($group)) {
1635 print "WARNING: Failed to clear devices from group '$group': ".
1636 $SCST->errorString()."\n";
1640 undef $ASSIGNMENTS{$group};
1649 my $root = new IO::Dir $_FC_CLASS_ if (-d $_FC_CLASS_);
1652 while (my $entry = $root->read()) {
1653 next if (($entry eq '.') || ($entry eq '..'));
1655 my $io = new IO::File "$_FC_CLASS_/$entry/port_name", O_RDONLY;
1662 $fcards{$entry} = $wwn;
1667 $root = new IO::Dir $_SCSI_CLASS_ if (-d $_SCSI_CLASS_);
1670 while (my $entry = $root->read()) {
1671 next if (($entry eq '.') || ($entry eq '..'));
1673 my $io = new IO::File "$_SCSI_CLASS_/$entry/target_mode_enabled", O_RDONLY;
1676 my $enabled = <$io>;
1680 $targets{$entry}->{'path'} = "$_SCSI_CLASS_/$entry/target_mode_enabled";
1681 $targets{$entry}->{'enabled'} = $enabled;
1682 $targets{$entry}->{'qla_isp'} = $FALSE;
1684 if ($fcards{$entry}) {
1685 $targets{$fcards{$entry}}->{'enabled'} = $enabled;
1686 $targets{$fcards{$entry}}->{'path'} =
1687 "$_SCSI_CLASS_/$entry/target_mode_enabled";
1689 if (-f "$_FC_CLASS_/$entry/issue_lip") {
1690 $targets{$fcards{$entry}}->{'ilip'} = "$_FC_CLASS_/$entry/issue_lip";
1693 $targets{$entry}->{'duplicate'} = $TRUE;
1695 $targets{$entry}->{'duplicate'} = $FALSE;
1701 $root = new IO::Dir $_SCSI_ISP_ if (-d $_SCSI_ISP_);
1704 while (my $entry = $root->read()) {
1705 next if (($entry eq '.') || ($entry eq '..'));
1708 my $io = new IO::File "$_SCSI_ISP_/$entry", O_RDONLY;
1718 ($wwn) = ($fstr =~ '.*?Port WWN +([^\ ]+) .*');
1719 $fcards{$entry} = $wwn;
1721 $io = new IO::File "$_SCSITGT_QLAISP_/$entry", O_RDONLY;
1726 ($enabled2) = ($fstr =~ '[^\n]+\n *\d *: *(\d)');
1727 $targets{$entry}->{'path'} = "$_SCSITGT_QLAISP_/$entry";
1728 $targets{$entry}->{'enabled'} = $enabled2;
1729 $targets{$entry}->{'qla_isp'} = $TRUE;
1731 if ($fcards{$entry}) {
1732 $targets{$fcards{$entry}}->{'enabled'} = $enabled2;
1733 $targets{$fcards{$entry}}->{'path'} = "$_SCSITGT_QLAISP_/$entry";
1734 $targets{$fcards{$entry}}->{'qla_isp'} = $TRUE;
1735 $targets{$entry}->{'duplicate'} = $TRUE;
1737 $targets{$entry}->{'duplicate'} = $FALSE;
1750 return undef if (!defined($$TARGETS{$target}));
1751 return $$TARGETS{$target}->{'enabled'};
1758 $target = unformatTarget($target);
1760 return undef if (!defined($$TARGETS{$target}));
1762 my $io = new IO::File $$TARGETS{$target}->{'path'}, O_WRONLY;
1763 return $TRUE if (!$io);
1765 print $enable ? "\t-> Enabling" : "\t-> Disabling";
1766 print " target mode for SCST host '$target'.\n";
1769 print "DBG($$): ".$$TARGETS{$target}->{'path'}." -> $enable\n\n";
1771 if ($$TARGETS{$target}->{'qla_isp'} == $FALSE) {
1774 print $io $enable ? "enable all" : "disable all";
1780 $$TARGETS{$target}->{'enabled'} = $enable;
1786 foreach my $target (keys %{$TARGETS}) {
1787 next if ($$TARGETS{$target}->{'duplicate'});
1788 next if (!$$TARGETS{$target}->{'enabled'});
1790 if (defined($$TARGETS{$target}->{'ilip'})) {
1791 my $io = new IO::File $$TARGETS{$target}->{'ilip'}, O_WRONLY;
1792 return $TRUE if (!$io);
1794 print "\t-> Issuing LIP for target '".formatTarget($target)."': ";
1797 print "DBG($$): ".$$TARGETS{$target}->{'ilip'}." -> $TRUE\n\n";
1808 my $confile = shift;
1809 my $ignoreError = shift;
1817 my $io = new IO::File $confile, O_RDONLY;
1820 return undef if ($ignoreError);
1822 die("FATAL: Unable to open specified configuration file $confile: $!\n");
1825 while (my $line = <$io>) {
1826 ($line, undef) = split(/\#/, $line, 2);
1827 $line = cleanupString($line);
1829 if ($line =~ /^\[(.*)\]$/) {
1830 ($section, $arg) = split(/\s+/, $1, 2);
1832 $arg = 'default' if ($section eq 'OPTIONS');
1834 if ($last_arg && ($last_arg ne $arg) &&
1835 !defined($config{$last_section}->{$last_arg})) {
1836 $config{$last_section}->{$last_arg} = \%empty;
1840 $last_section = $section;
1841 } elsif ($section && $arg && $line) {
1842 my($parameter, $value) = split(/\s+/, $line, 2);
1844 if ($section eq 'OPTIONS') {
1845 $value = $TRUE if (($value == 1) ||
1846 ($value =~ /^TRUE$/i) ||
1847 ($value =~ /^YES$/i));
1848 $value = $FALSE if (($value == 0) ||
1849 ($value =~ /^FALSE$/i) ||
1850 ($value =~ /^NO$/i));
1853 push @{$config{$section}->{$arg}->{$parameter}}, $value;
1866 foreach my $group (keys %{$$config{'GROUP'}}) {
1867 foreach my $_user (@{$$config{'GROUP'}->{$group}->{'USER'}}) {
1868 return $group if ($_user eq $user);
1875 sub findUserGroupInCurrent {
1878 foreach my $group (keys %USERS) {
1879 foreach my $_user (keys %{$USERS{$group}}) {
1880 return $group if ($_user eq $user);
1887 sub findAssignedLun {
1888 my $associations = shift;
1891 return undef if (!defined($lun));
1893 foreach my $device (keys %{$associations}) {
1894 if ($$associations{$device} == $lun) {
1905 $string =~ s/^\s+//;
1906 $string =~ s/\s+$//;
1914 if ($target =~ /^0x/) {
1916 my($o1, $o2, $o3, $o4, $o5, $o6, $o7, $o8) = unpack("A2A2A2A2A2A2A2A2", $target);
1917 $target = "$o1:$o2:$o3:$o4:$o5:$o6:$o7:$o8";
1920 $target =~ tr/A-Z/a-z/;
1925 sub unformatTarget {
1928 if ($target =~ /^.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}/) {
1930 $target = "0x$target";
1933 $target =~ tr/A-Z/a-z/;
1938 sub validHandlerTypes {
1942 foreach my $handler (keys %_REVERSE_MAP_) {
1943 $buffer .= "\t".$_REVERSE_MAP_{$handler}."\n" if ($SCST->handlerType($handler) == $type);
1950 return int(rand(10000));
1953 # If we have an unread error from SCST, exit immediately
1957 return if (!$error);
1959 print "\n\nFATAL: Received the following error:\n\n\t";
1967 print "\n\nAborting immediately.\n";