- Fix really stupid mistake where config commits were using same path
[mirror/scst/.git] / scstadmin / scstadmin
index e4e1f91..64a6680 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl
-$Version  = 'SCST Configurator v0.6';
+$Version  = 'SCST Configurator v0.7.1';
 
 # Configures SCST
 #
@@ -59,10 +59,10 @@ Debugging (limited support)
      -debug               : Debug mode - don\'t do anything destructive.
 
 Available Handlers:
-      disk, disk_fileio, disk_perf, cdrom, changer, modisk, modisk_perf, tape, tape_perf
+      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
+      WRITE_THROUGH, READ_ONLY, O_DIRECT, NULLIO, NV_CACHE, BIO
      
 Examples:
      Enable target mode for fibre card specifying its WWN
@@ -75,7 +75,7 @@ Examples:
        scstadmin -addgroup HOST01
        
      Create a device given an already existing disk file:
-       scstadmin -adddev DISK01 -handler disk_fileio -path /vdisks/disk01.dsk -options READ_ONLY,WRITE_THROUGH
+       scstadmin -adddev DISK01 -handler vdisk -path /vdisks/disk01.dsk -options READ_ONLY,WRITE_THROUGH
        
      Assign a device to a security group:
        scstadmin -assigndev DISK01 -group HOST01 -lun 1
@@ -113,27 +113,45 @@ my $_DEBUG_;
 my %_HANDLER_MAP_ = ('cdrom' => $SCST::SCST::CDROM_TYPE,
                     'changer' => $SCST::SCST::CHANGER_TYPE,
                     'disk' => $SCST::SCST::DISK_TYPE,
-                    'disk_fileio' => $SCST::SCST::DISKFILE_TYPE,
-                    'cdrom_fileio' => $SCST::SCST::CDROMFILE_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);
+                    '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::DISKFILE_TYPE => 'disk_fileio',
-                    $SCST::SCST::CDROMFILE_TYPE => 'cdrom_fileio',
+                    $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::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();
@@ -254,7 +272,7 @@ sub getArgs {
        }
 
        if ($releaseDev && !defined($group)) {
-               print "Please specify -group with -RemoveDev.\n\n";
+               print "Please specify -group with -ReleaseDev.\n\n";
                usage();
        }
 
@@ -268,6 +286,8 @@ sub getArgs {
                usage();
        }
 
+       $_DEBUG_ = $TRUE if (defined($_DEBUG_));
+
        $forceConfig = $TRUE if (defined($forceConfig));
        $showSessions = $TRUE if (defined($showSessions));
 
@@ -306,7 +326,7 @@ sub main {
 
        $SCST = new SCST::SCST($_DEBUG_);
 
-       readCurrentConfig();
+       readWorkingConfig();
 
        SWITCH: {
                $applyConfig && do {
@@ -318,6 +338,7 @@ sub main {
                                sleep 10;
                        }
 
+                       readWorkingConfig();
                        $rc = applyConfiguration($applyConfig, $forceConfig, $FALSE);
                        last SWITCH;
                };
@@ -398,11 +419,19 @@ sub main {
        exit $rc;
 }
 
-sub readCurrentConfig {
+sub readWorkingConfig {
        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
        }
@@ -410,10 +439,13 @@ sub readCurrentConfig {
        $TARGETS = targets();
 
        $DEVICES = $SCST->devices();
+       immediateExit($SCST->errorString());
+
        my $_eGroups = $SCST->groups();
+       immediateExit($SCST->errorString());
 
        foreach my $group (@{$_eGroups}) {
-               $GROUPS{$group}++; # For quick lookups
+               $GROUPS{$group}++;
                $ASSIGNMENTS{$group} = $SCST->groupDevices($group);
                my $eUsers = $SCST->users($group);
 
@@ -422,7 +454,7 @@ sub readCurrentConfig {
                }
        }
 
-       print "done.\n";
+       print "done.\n\n";
 }
 
 sub writeConfiguration {
@@ -445,14 +477,27 @@ sub writeConfiguration {
 
        print "Writing current configuration to file '$file'.. ";
 
-       print $io "# Automatically generated by scst.\n\n";
+       print $io "# Automatically generated by $Version.\n\n";
 
        # Device information
        foreach my $handler (sort keys %HANDLERS) {
                print $io "[HANDLER ".$_REVERSE_MAP_{$handler}."]\n";
 
+               if ($SCST->handlerType($handler) == $SCST::SCST::IOTYPE_VIRTUAL) {
+                       print $io "#DEVICE <vdisk name>,<device path>";
+                       if ($handler == $SCST::SCST::VDISK_TYPE) {
+                               print $io ",<options>,<block size>\n";
+                       } else {
+                               print $io "\n";
+                       }
+               } else {
+                       print $io "#DEVICE <H:C:I:L>\n";
+               }
+
                my $devices = $SCST->handlerDevices($handler);
 
+               immediateExit($SCST->errorString());
+
                foreach my $device (sort keys %{$devices}) {
                        my $options = $$devices{$device}->{'OPTIONS'};
                        $options =~ s/\,/\|/;
@@ -469,6 +514,7 @@ sub writeConfiguration {
        # User configuration
        foreach my $group (sort keys %USERS) {
                print $io "[GROUP $group]\n";
+               print $io "#USER <user wwn>\n";
 
                foreach my $user (keys %{$USERS{$group}}) {
                        print $io "USER $user\n";
@@ -480,6 +526,7 @@ sub writeConfiguration {
        # Assignments configuration
        foreach my $group (sort keys %ASSIGNMENTS) {
                print $io "[ASSIGNMENT $group]\n";
+               print $io "#DEVICE <device name>,<lun>\n";
 
                my $pointer = $ASSIGNMENTS{$group};
                foreach my $device (sort keys %{$pointer}) {
@@ -492,6 +539,7 @@ sub writeConfiguration {
        # Targets configuration
        foreach my $type ('enable', 'disable') {
                print $io "[TARGETS $type]\n";
+               print $io "#HOST <wwn identifier>\n";
 
                foreach my $target (sort keys %{$TARGETS}) {
                        if ((($type eq 'enable') && $$TARGETS{$target}->{'enabled'}) ||
@@ -523,185 +571,75 @@ sub applyConfiguration {
        my %used_users;
        my %used_assignments;
 
-       print "Applying configurations additions..\n" if (!$check);
-       print "\n";
-
-       # 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-force: Target mode for '$target' is currently enabled, ".
-                                         "however configuration file wants it disabled";
-
-                                       if (!$check) {
-                                               print ", disabling.\n";
-                                               $errs += enableTarget($target, $enable);
-                                       } else {
-                                               print ".\n";
-                                       }
-
-                                       $changes++;
-                               }
-                       } else {
-                               print "\t-> Target '$target' is enabled in configuration file, ".
-                                 "however is currently disabled";
-
-                               if (!$check) {
-                                       print ", enabling.\n";
-                                       $errs += enableTarget($target, $enable);
-                               } else {
-                                       print ".\n";
-                               }
-
-                               $changes++;
-                       }
-               }
-       }
-
-       # Open new devices and assign them to handlers..
+       # Cache device/handler configuration
        foreach my $entry (keys %{$$config{'HANDLER'}}) {
-               if (!$HANDLERS{$_HANDLER_MAP_{$entry}}) {
-                       print "\t-> WARNING: Handler '$entry' does not exist.\n";
-                       $errs += 1;
-                       next;
-               }
-
                foreach my $device (@{$$config{'HANDLER'}->{$entry}->{'DEVICE'}}) {
-                       my($vname, $path, $options, $blocksize) = split(/\,/, $device);
+                       my($vname, undef) = split(/\,/, $device, 2);
                        $vname = cleanupString($vname);
-                       $path = cleanupString($path);
-
-                       $options =~ s/\s+//; $options =~ s/\|/,/;
-
                        $used_devs{$vname} = $entry;
-
-                       next if (defined($$DEVICES{$vname}));
-
-                       $changes++;
-
-                       if ($check) {
-                               print "\t-> New device '$entry:$vname' at path '$path', options '$options', blocksize $blocksize.\n";
-                               $$DEVICES{$vname} = $_HANDLER_MAP_{$entry};
-                       } else {
-                               $errs += addDevice($entry, $vname, $path, $options, $blocksize);
-                       }
                }
        }
 
-       # Create new groups and add users..
+       # Cache user/group configuration
        foreach my $group (keys %{$$config{'GROUP'}}) {
-               if (!defined($GROUPS{$group})) {
-                       $changes++;
-
-                       if ($check) {
-                               print "\t-> New group definition '$group.'\n";
-                               $GROUPS{$group}++;
-                       } else {
-                               $errs += addGroup($group);
-                       }
-               }
-
                foreach my $user (@{$$config{'GROUP'}->{$group}->{'USER'}}) {
                        $used_users{$group}->{$user}++;
-
-                       if (!defined($USERS{$group}->{$user})) {
-                               $changes++;
-
-                               if ($check) {
-                                       print "\t-> New user definition '$user' for group '$group'.\n";
-                                       $USERS{$group}->{$user}++;
-                               } else {
-                                       $errs += addUser($group, $user);
-                               }
-                       }
                }
        }
 
-       # Assign new devices to groups..
+       # Cache device association configuration
        foreach my $group (keys %{$$config{'ASSIGNMENT'}}) {
-               if (!defined($GROUPS{$group})) {
-                       print "\t-> WARNING: Unable to assign to non-existant group '$group'.\n";
-                       $errs += 1;
-                       next;
-               }
-
                foreach my $device (@{$$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
                        my($vname, $lun) = split(/\,/, $device);
                        $vname = cleanupString($vname);
-                       $lun = cleanupString($lun);
-
-                       $used_assignments{$group}->{$vname}++;
-
-                       my $_assignments = $ASSIGNMENTS{$group};
-                       next if (defined($$_assignments{$vname}));
-
-                       $changes++;
-
-                       if ($check) {
-                               $lun = 'auto' if (!defined($lun));
-                               print "\t-> New device assignment for '$vname' to group '$group' at LUN $lun.\n";
-                       } else {
-                               $errs += assignDevice($group, $vname, $lun);
-                       }
+                       $used_assignments{$group}->{$vname} = $lun;
                }
        }
 
        # If -ForceConfig is used, check for configurations which we've deleted but are still active.
        if ($force || $check) {
-               readCurrentConfig() if (!$check);
-
                # Associations
                foreach my $group (sort keys %ASSIGNMENTS) {
-                       if (!defined($used_assignments{$group})) {
-                               print "\t-force: Group $group has no associations in saved configuration";
+                       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";
-                                       $errs += clearDevices($group);
+                                       if (clearDevices($group)) {
+                                               $errs++;
+                                       } else {
+                                               $changes++;
+                                       }
                                } else {
                                        print ".\n";
+                                       $changes++;
                                }
-
-                               $changes++;
                        } else {
                                my $_assignments = $ASSIGNMENTS{$group};
 
                                foreach my $device (sort keys %{$_assignments}) {
-                                       if (!defined($used_assignments{$group}->{$device})) {
-                                               print "\t-force: Device $device is not associated with group ".
-                                                 "$group in saved configuration";
+                                       if (!defined($used_assignments{$group}->{$device}) ||
+                                          ($$_assignments{$device} != $used_assignments{$group}->{$device})) {
+                                               if ($$_assignments{$device} != $used_assignments{$group}->{$device}) {
+                                                       print "\t-> WARNING: Device '$device' assigned to group '$group' is at LUN ".
+                                                         $used_assignments{$group}->{$device}.
+                                                         " whereas working configuration reflects LUN ".$$_assignments{$device}; 
+                                               } else {
+                                                       print "\t-> WARNING: Device '$device' is not associated with group ".
+                                                         "'$group' in saved configuration";
+                                               }
 
                                                if (!$check) {
                                                        print ", releasing.\n";
-                                                       $errs += releaseDevice($group, $device);
+                                                       if (releaseDevice($group, $device)) {
+                                                               $errs++;
+                                                       } else {
+                                                               $changes++;
+                                                       }
                                                } else {
                                                        print ".\n";
+                                                       $changes++;
                                                }
-
-                                               $changes++;
                                        }
                                }
                        }
@@ -710,31 +648,42 @@ sub applyConfiguration {
                # Users & Groups
                foreach my $group (sort keys %USERS) {
                        if (!defined($used_users{$group})) {
-                               print "\t-force: Group $group does not exist in saved configuration";
+                               print "\t-> WARNING: Group '$group' does not exist in saved configuration";
 
                                if (!$check) {
                                        print ", removing.\n";
-                                       $errs += clearUsers($group);
-                                       $errs += removeGroup($group);
+                                       if (clearUsers($group)) {
+                                               $errs++;
+                                       } else {
+                                               $changes++;
+                                       }
+
+                                       if (removeGroup($group)) {
+                                               $errs++;
+                                       } else {
+                                               $changes++;
+                                       }
                                } else {
                                        print ".\n";
+                                       $changes++;
                                }
-
-                               $changes++;
                        } else {
                                foreach my $user (sort keys %{$USERS{$group}}) {
                                        if (!defined($used_users{$group}->{$user})) {
-                                               print "\t-force: User $user is not defined as part of group $group ".
+                                               print "\t-> WARNING: User '$user' is not defined as part of group '$group' ".
                                                  "in saved configuration";
 
                                                if (!$check) {
                                                        print ", removing.\n";
-                                                       $errs += removeUser($group, $user);
+                                                       if (removeUser($group, $user)) {
+                                                               $errs++;
+                                                       } else {
+                                                               $changes++;
+                                                       }
                                                } else {
                                                        print ".\n";
+                                                       $changes++;
                                                }
-
-                                               $changes++;
                                        }
                                }
                        }
@@ -743,27 +692,30 @@ sub applyConfiguration {
                # Devices
                foreach my $device (sort keys %{$DEVICES}) {
                        if ($$DEVICES{$device} && !defined($used_devs{$device})) {
-                               # Device gone, but is it still assigned tp a group?
+                               # 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-force: WARNING: Device $device is not defined in saved configuration, ".
-                                                 "however, it is still assigned to group $group! Ignoring removal.\n";
+                                               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) {
-                                       print "\t-force: Device $device is not defined in saved configuration";
+                               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";
-                                               $errs += removeDevice($device);
+                                               if (removeDevice($device)) {
+                                                       $errs++;
+                                               } else {
+                                                       $changes++;
+                                               }
                                        } else {
                                                print ".\n";
+                                               $changes++;
                                        }
-
-                                       $changes++;
                                }
                        } else {
                                # Handler change
@@ -771,18 +723,192 @@ sub applyConfiguration {
                                        my $handler = $used_devs{$device};
 
                                        if ($HANDLERS{$_HANDLER_MAP_{$handler}}) {
-                                               print "\t-force: Device $device changes handler to $handler";
+                                               print "\t-> WARNING: Device '$device' changes handler to '$handler'";
 
                                                if (!$check) {
                                                        print ", changing.\n";
-                                                       $errs += assignDeviceToHandler($device, $handler);
-
+                                                       if ($SCST->assignDeviceToHandler($device,
+                                                                                        $_HANDLER_MAP_{$handler})) {
+                                                               $errs++;
+                                                       } else {
+                                                               $changes++;
+                                                       }
                                                } else {
                                                        print ".\n";
+                                                       $changes++;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       print "Applying configurations additions..\n" if (!$check);
+       print "\n";
+
+       readWorkingConfig() if ($force);
+
+       foreach my $_handler (sort keys %{$$config{'HANDLER'}}) {
+               if (!$HANDLERS{$_HANDLER_MAP_{$_handler}}) {
+                       print "\t-> WARNING: Handler '$_handler' does not exist.\n";
+                       $errs += 1;
+                       next;
+               }
+
+               foreach my $device (@{$$config{'HANDLER'}->{$_handler}->{'DEVICE'}}) {
+                       my($vname, $path, $options, $blocksize) = split(/\,/, $device);
+                       $path = cleanupString($path);
+                       $options =~ s/\s+//; $options =~ s/\|/,/;
+
+                       if (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} == $$DEVICES{$vname})) {
+                               next;
+                       } elsif (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} != $$DEVICES{$vname})) {
+                               if ($HANDLERS{$_HANDLER_MAP_{$_handler}}) {
+                                       print "\t-> WARNING: Device '$vname' changes handler from '".
+                                         $_REVERSE_MAP_{$$DEVICES{$vname}}."' to '$_handler'.\n".
+                                         "\t   Use -ForceConfig to change device handler.\n" if (!$force && !$check);
+                               }
+                               next;
+                       }
+
+                       if ($check) {
+                               print "\t-> New device '$_handler:$vname' at path '$path', options '$options', ".
+                                 "blocksize $blocksize.\n";
+                               $$DEVICES{$vname} = $_HANDLER_MAP_{$_handler};
+                               $changes++;
+                       } else {
+                               if (addDevice($_handler, $vname, $path, $options, $blocksize)) {
+                                       $errs++;
+                               } else {
+                                       $changes++;
+                               }
+                       }
+               }
+       }
+
+       # Create new groups and add users..
+       foreach my $group (keys %used_users) {
+               if (!defined($USERS{$group})) {
+                       if ($check) {
+                               print "\t-> New group definition '$group.'\n";
+                               $GROUPS{$group}++;
+                               $changes++;
+                       } else {
+                               if (addGroup($group)) {
+                                       $errs++;
+                               } else {
+                                       $changes++;
+                               }
+                       }
+               }
+
+               foreach my $user (keys %{$used_users{$group}}) {
+                       if (!defined($USERS{$group}->{$user})) {
+                               if ($check) {
+                                       print "\t-> New user definition '$user' for group '$group'.\n";
+                                       $USERS{$group}->{$user}++;
+                                       $changes++;
+                               } else {
+                                       if (addUser($group, $user)) {
+                                               $errs++;
+                                       } else {
+                                               $changes++;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       # Assign new devices to groups..
+       foreach my $group (keys %used_assignments) {
+               if (!defined($GROUPS{$group})) {
+                       print "\t-> WARNING: Unable to assign to non-existant group '$group'.\n";
+                       $errs += 1;
+                       next;
+               }
+
+               foreach my $vname (keys %{$used_assignments{$group}}) {
+                       my $lun = $used_assignments{$group}->{$vname};
+                       my $_assignments = $ASSIGNMENTS{$group};
+
+                       if (defined($$_assignments{$vname}) && ($$_assignments{$vname} == $lun)) {
+                               next;
+                       } elsif (defined($$_assignments{$vname}) && ($$_assignments{$vname} != $lun)) {
+                               print "\t-> Device '$vname' assigned to group '$group' is at LUN ".$$_assignments{$vname}.
+                                 ", whereas the working configuration reflects LUN $lun.\n".
+                                 "\t   Use -ForceConfig to force this LUN change.\n" if (!$force && !$check);
+                       } else {
+                               if ($check) {
+                                       $lun = 'auto' if (!defined($lun));
+                                       print "\t-> New device assignment for '$vname' to group '$group' at LUN $lun.\n";
+                                       $changes++;
+                               } else {
+                                       if (assignDevice($group, $vname, $lun)) {
+                                               $errs++;
+                                       } else {
+                                               $changes++;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       # Enable/Disable configured targets
+       foreach my $type (keys %{$$config{'TARGETS'}}) {
+               my $enable;
+
+               if ($type eq 'enable') {
+                       $enable = $TRUE;
+               } elsif ($type eq 'disable') {
+                       $enable = $FALSE;
+               } else {
+                       print "\t-> WARNING: Ignoring invalid TARGETS specifier '$type'. ".
+                         "Should be one of enable,disable.\n";
+                       next;
+               }
+
+               foreach my $target (@{$$config{'TARGETS'}->{$type}->{'HOST'}}) {
+                       my $i_target = unformatTarget($target);
+
+                       if (!defined($$TARGETS{$i_target})) {
+                               print "\t-> WARNING: Target '$target' not found on system.\n";
+                               $errs += 1;
+                               next;
+                       }
+
+                       next if ($enable == targetEnabled($i_target));
+
+                       if (!$enable && targetEnabled($target)) {
+                               if ($force || $check) {
+                                       print "\t-> WARNING: Target mode for '$target' is currently enabled, ".
+                                         "however configuration file wants it disabled";
+
+                                       if (!$check) {
+                                               print ", disabling.\n";
+                                               if (enableTarget($target, $enable)) {
+                                                       $errs++;
+                                               } else {
+                                                       $changes++;
                                                }
+                                       } else {
+                                               print ".\n";
+                                               $changes++;
+                                       }
+                               }
+                       } else {
+                               print "\t-> Target '$target' is enabled in configuration file, ".
+                                 "however is currently disabled";
 
+                               if (!$check) {
+                                       print ", enabling.\n";
+                                       if (enableTarget($target, $enable)) {
+                                               $errs++;
+                                       } else {
                                                $changes++;
                                        }
+                               } else {
+                                       print ".\n";
+                                       $changes++;
                                }
                        }
                }
@@ -791,7 +917,7 @@ sub applyConfiguration {
        print "\nEncountered $errs error(s) while processing.\n" if ($errs);
 
        if ($check) {
-               print "Configuration checked, $changes difference(s) found with current configuration.\n";
+               print "Configuration checked, $changes difference(s) found with working configuration.\n";
        } else {
                $changes = 0 if ($_DEBUG_);
                print "Configuration applied, $changes changes made.\n";
@@ -815,6 +941,8 @@ sub clearConfiguration {
 
        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);
        }
 
@@ -827,6 +955,7 @@ sub clearConfiguration {
 
 sub showSessions {
        my $sessions = $SCST->sessions();
+       immediateExit($SCST->errorString());
 
        print "\n\tTarget Name\tInitiator Name\t\t\tGroup Name\t\tCommand Count\n";
 
@@ -855,6 +984,21 @@ sub addDevice {
        $options =~ s/\,/ /;
 
        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";
@@ -864,7 +1008,8 @@ sub addDevice {
        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'.\n";
+               print "WARNING: Failed to open virtual device '$device' at path '$path': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -878,6 +1023,21 @@ sub removeDevice {
        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";
@@ -887,7 +1047,8 @@ sub removeDevice {
        print "\t-> Closing virtual device '$device'..\n";
 
        if ($SCST->closeDevice($_handler, $device)) {
-               print "WARNING: Failed to close virtual device '$device'.\n";
+               print "WARNING: Failed to close virtual device '$device': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -907,7 +1068,8 @@ sub addGroup {
        print "\t-> Creating security group '$group'..\n";
 
        if ($SCST->addGroup($group)) {
-               print "WARNING: Failed to create security group '$group'.\n";
+               print "WARNING: Failed to create security group '$group': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -927,7 +1089,8 @@ sub removeGroup {
        print "\t-> Removing security group '$group'..\n";
 
        if ($SCST->removeGroup($group)) {
-               print "WARNING: Failed to remove security group '$group'.\n";
+               print "WARNING: Failed to remove security group '$group': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -953,7 +1116,8 @@ sub addUser {
        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'.\n";
+               print "WARNING: Failed to add user '$user' to security group '$group': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -979,7 +1143,8 @@ sub removeUser {
        print "\t-> Removing user '$user' from security group '$group'..\n";
 
        if ($SCST->removeUser($user, $group)) {
-               print "WARNING: Failed to add user '$user' to security group '$group'.\n";
+               print "WARNING: Failed to add user '$user' to security group '$group': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -999,7 +1164,8 @@ sub clearUsers {
        print "\t-> Clearing users from security group '$group'..\n";
 
        if ($SCST->clearUsers($group)) {
-               print "WARNING: Failed to clear users from security group '$group'.\n";
+               print "WARNING: Failed to clear users from security group '$group': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -1052,7 +1218,8 @@ sub assignDevice {
        print "\t-> Assign virtual device '$device' to group '$group' at LUN '$lun'..\n";
 
        if ($SCST->assignDeviceToGroup($device, $group, $lun)) {
-               print "WARNING: Failed to assign device '$device' to group '$group'.\n";
+               print "WARNING: Failed to assign device '$device' to group '$group': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -1085,7 +1252,8 @@ sub releaseDevice {
        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'.\n";
+               print "WARNING: Failed to release device '$device' from group '$group': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -1107,7 +1275,8 @@ sub clearDevices {
        print "\t-> Clear virtual devices from group '$group'..\n";
 
        if ($SCST->clearGroupDevices($group)) {
-               print "WARNING: Failed to clear devices from group '$group'.\n";
+               print "WARNING: Failed to clear devices from group '$group': ".
+                 $SCST->errorString()."\n";
                return $TRUE;
        }
 
@@ -1218,6 +1387,7 @@ sub readConfig {
                        ($section, $arg) = split(/\s+/, $1, 2);
                } elsif ($section && $arg && $line) {
                        my($parameter, $value) = split(/\s+/, $line, 2);
+
                        push @{$config{$section}->{$arg}->{$parameter}}, $value;
                }
        }
@@ -1263,6 +1433,29 @@ sub unformatTarget {
        return $target;
 }
 
+sub validHandlerTypes {
+       my $type = shift;
+       my $buffer = "\n";
+
+       foreach my $handler (keys %_REVERSE_MAP_) {
+               $buffer .= "\t".$_REVERSE_MAP_{$handler}."\n" if ($SCST->handlerType($handler) == $type);
+       }
+
+       return $buffer;
+}
+
+# If we have an unread error from SCST, exit immediately
+sub immediateExit {
+       my $error = shift;
+
+       return if (!$error);
+
+       print "\n\nFATAL: Received the following error:\n\n\t";
+       print "$error\n\n";
+
+       exit 1;
+}
+
 # Hey! Stop that!
 sub commitSuicide {
        print "\n\nAborting immediately.\n";