391cff5309c84942b304a29d3edefd51c0f98661
[mirror/scst/.git] / scstadmin / scstadmin
1 #!/usr/bin/perl
2 $Version  = 'SCST Configurator v1.0.5';
3
4 # Configures SCST
5 #
6 # Author:       Mark R. Buechler
7 # License:      GPLv2
8 # Copyright (c) 2005-2007 Mark R. Buechler
9
10 sub usage
11   {
12     die <<"EndUsage";
13 $Version
14
15 Usage:
16 General Operations
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.
22      
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
27 Devices Operations
28      -adddev <device>     : Adds a device to a handler.
29          -handler <handler>
30          -path <path>
31          -options <options>
32          -blocksize <bytes>
33      -RemoveDev <device>  : Remove a device from a handler.
34          -handler <handler>
35  
36 Users Operations
37      -adduser <user>      : Adds a user to a security group.
38          -group <group>
39      -RemoveUser <user>   : Delete a user from a security group.
40          -group <group>
41      -ClearUsers          : Clear all users from a given security group.
42          -group <group>
43
44 Groups Operations
45      -addgroup <group>    : Add a given group to available security groups.
46      -RemoveGroup <group> : Remove a give group from available security groups.
47      
48 Assignments Operations
49      -assigndev <device>  : Assign a given device to a security group.
50          -group <group>
51          -lun <lun>
52      -ReleaseDev <device> : Remove a given device from a security group.
53          -group <group>
54      -ClearDevs           : Clear all device assignments for a security group.
55          -group <group>
56
57 Options
58      -ForceConfig         : Force all configuration changes, even deletions (DANGER!).
59   
60 Debugging (limited support)
61      -debug               : Debug mode - don\'t do anything destructive.
62
63 Available Handlers:
64       disk, vdisk, disk_perf, cdrom, vcdrom, changer, modisk, modisk_perf, tape, tape_perf
65
66 Available Options for create and open:
67       WRITE_THROUGH, READ_ONLY, O_DIRECT, NULLIO, NV_CACHE, BLOCK_IO, REMOVABLE
68
69 Examples:
70      Enable target mode for fibre card specifying its WWN
71        scstadmin -enable 50:06:0B:00:00:39:71:78
72
73      Disable target mode for SCSI host specifying host number
74        scstadmin -disable host4 
75
76      Create a new security group:
77        scstadmin -addgroup HOST01
78        
79      Create a device given an already existing disk file:
80        scstadmin -adddev DISK01 -handler vdisk -path /vdisks/disk01.dsk -options READ_ONLY,WRITE_THROUGH
81        
82      Assign a device to a security group:
83        scstadmin -assigndev DISK01 -group HOST01 -lun 1
84
85 EndUsage
86   }
87
88 use SCST::SCST;
89 use Getopt::Long;
90 use IO::File;
91 use IO::Dir;
92 use POSIX;
93 use strict;
94
95 my $_DEF_CONFIG_ = '/etc/scst.conf';
96
97 my $TRUE  = 1;
98 my $FALSE = 0;
99
100 my $_MAX_LUNS_       = 255;
101 my $_DEFAULT_GROUP_  = 'Default';
102
103 my $_SCSI_CLASS_     = '/sys/class/scsi_host';
104 my $_FC_CLASS_       = '/sys/class/fc_host';
105 my $_SCSI_ISP_       = '/proc/scsi/isp';
106 my $_SCSITGT_QLAISP_ = '/proc/scsi_tgt/qla_isp';
107
108 my $SCST;
109 my $DEVICES;
110 my $TARGETS;
111 my %USERS;
112 my %ASSIGNMENTS;
113 my %HANDLERS;
114 my %GROUPS;
115 my $_DEBUG_;
116
117 my %_HANDLER_MAP_ = ('cdrom' => $SCST::SCST::CDROM_TYPE,
118                      'changer' => $SCST::SCST::CHANGER_TYPE,
119                      'disk' => $SCST::SCST::DISK_TYPE,
120                      'vdisk' => $SCST::SCST::VDISK_TYPE,
121                      'vcdrom' => $SCST::SCST::VCDROM_TYPE,
122                      'disk_perf' => $SCST::SCST::DISKPERF_TYPE,
123                      'modisk' => $SCST::SCST::MODISK_TYPE,
124                      'modisk_perf' => $SCST::SCST::MODISKPERF_TYPE,
125                      'tape' => $SCST::SCST::TAPE_TYPE,
126                      'tape_perf' => $SCST::SCST::TAPEPERF_TYPE,
127                      'processor' => $SCST::SCST::PROCESSOR_TYPE,
128                 # Add in the dev_ names as well
129                      'dev_cdrom' => $SCST::SCST::CDROM_TYPE,
130                      'dev_changer' => $SCST::SCST::CHANGER_TYPE,
131                      'dev_disk' => $SCST::SCST::DISK_TYPE,
132                      'dev_disk_perf' => $SCST::SCST::DISKPERF_TYPE,
133                      'dev_modisk' => $SCST::SCST::MODISK_TYPE,
134                      'dev_modisk_perf' => $SCST::SCST::MODISKPERF_TYPE,
135                      'dev_tape' => $SCST::SCST::TAPE_TYPE,
136                      'dev_tape_perf' => $SCST::SCST::TAPEPERF_TYPE,
137                      'dev_processor' => $SCST::SCST::PROCESSOR_TYPE);
138                      
139 my %_REVERSE_MAP_ = ($SCST::SCST::CDROM_TYPE => 'cdrom',
140                      $SCST::SCST::CHANGER_TYPE => 'changer',
141                      $SCST::SCST::DISK_TYPE => 'disk',
142                      $SCST::SCST::VDISK_TYPE => 'vdisk',
143                      $SCST::SCST::VCDROM_TYPE => 'vcdrom',
144                      $SCST::SCST::DISKPERF_TYPE => 'disk_perf',
145                      $SCST::SCST::MODISK_TYPE => 'modisk',
146                      $SCST::SCST::MODISKPERF_TYPE => 'modisk_perf',
147                      $SCST::SCST::TAPE_TYPE => 'tape',
148                      $SCST::SCST::TAPEPERF_TYPE => 'tape_perf',
149                      $SCST::SCST::PROCESSOR_TYPE => 'processor');
150
151 my %_HANDLER_TYPE_MAP_ = ($SCST::SCST::IOTYPE_PHYSICAL => 'physical',
152                           $SCST::SCST::IOTYPE_VIRTUAL => 'virtual',
153                           $SCST::SCST::IOTYPE_PERFORMANCE => 'performance');
154
155 $SIG{INT} = \&commitSuicide;
156
157 use vars qw($Version);
158
159 POSIX::setsid();
160
161 &main();
162
163 sub getArgs {
164         my $applyConfig;
165         my $forceConfig;
166         my $clearConfig;
167         my $writeConfig;
168         my $checkConfig;
169         my $showSessions;
170         my $addDev;
171         my $devPath;
172         my $removeDev;
173         my $addUser;
174         my $removeUser;
175         my $clearUsers;
176         my $addGroup;
177         my $removeGroup;
178         my $assignDev;
179         my $releaseDev;
180         my $clearDevs;
181         my $devLun;
182         my $handler;
183         my $group;
184         my $options;
185         my $blocksize;
186         my $enable;
187         my $disable;
188
189         my $p = new Getopt::Long::Parser;
190
191         if (!$p->getoptions('config:s'          => \$applyConfig,
192                             'ClearConfig'       => \$clearConfig,
193                             'ForceConfig'       => \$forceConfig,
194                             'WriteConfig=s'     => \$writeConfig,
195                             'checkConfig=s'     => \$checkConfig,
196                             'sessions'          => \$showSessions,
197                             'adddev=s'          => \$addDev,
198                             'path=s'            => \$devPath,
199                             'RemoveDev=s'       => \$removeDev,
200                             'lun=s'             => \$devLun,
201                             'adduser=s'         => \$addUser,
202                             'RemoveUser=s'      => \$removeUser,
203                             'ClearUsers'        => \$clearUsers,
204                             'addgroup=s'        => \$addGroup,
205                             'RemoveGroup=s'     => \$removeGroup,
206                             'assigndev=s'       => \$assignDev,
207                             'ReleaseDev=s'      => \$releaseDev,
208                             'ClearDevs'         => \$clearDevs,
209                             'handler=s'         => \$handler,
210                             'group=s'           => \$group,
211                             'options=s'         => \$options,
212                             'blocksize=s'       => \$blocksize,
213                             'enable=s'          => \$enable,
214                             'disable=s'         => \$disable,
215                             'debug'             => \$_DEBUG_)) {
216                 &usage();
217         }
218
219         if ((defined($enable) && !$enable) || (defined($disable) && !$disable)) {
220                 print "Argument -enable/-disable requires a WWN or host.\n\n";
221                 usage();
222         }
223
224         if ($handler && !$_HANDLER_MAP_{$handler}) {
225                 print "Invalid handler '$handler' specified. Available handlers are:\n\n";
226                 foreach my $_handler (keys %_HANDLER_MAP_) {
227                         print "\t$_handler\n";
228                 }
229                 print "\n";
230                 exit 1;
231         }
232
233         if ($addDev && !($handler && $devPath)) {
234                 print "Please specify -handler and -path with -adddev.\n\n";
235                 usage();
236         }
237
238         if (defined($blocksize) && !$blocksize) {
239                 print "Please specify bytes with -blocksize.\n\n";
240                 usage();
241         }
242
243         if ($blocksize && !$addDev) {
244                 print "Please specify -adddev with -blocksize.\n";
245                 usage();
246         }
247
248         if (defined($forceConfig) && !defined($applyConfig)) {
249                 print "Please specify -config with -ForceConfig.\n\n";
250                 usage();
251         }
252
253         if ($removeDev && !$handler) {
254                 print "Please specify -handler with -RemoveDev.\n\n";
255                 usage();
256         }
257
258         if ($addUser && !defined($group)) {
259                 print "Please specify -group with -adduser.\n\n";
260                 usage();
261         }
262
263         if ($removeUser && !defined($group)) {
264                 print "Please specify -group with -RemoveUser.\n\n";
265                 usage();
266         }
267
268         if ($clearUsers && !defined($group)) {
269                 print "Please specify -group with -ClearUsers.\n\n";
270                 usage();
271         }
272
273         if ($assignDev && !(defined($group) && defined($devLun))) {
274                 print "Please specify -group and -lun with -assigndev.\n\n";
275                 usage();
276         }
277
278         if ($releaseDev && !defined($group)) {
279                 print "Please specify -group with -ReleaseDev.\n\n";
280                 usage();
281         }
282
283         if ($clearDevs && !defined($group)) {
284                 print "Please specify -group with -ClearDevs.\n\n";
285                 usage();
286         }
287
288         if (defined($writeConfig) && !$writeConfig) {
289                 print "Please specify a file name to write configuration to..\n\n";
290                 usage();
291         }
292
293         $_DEBUG_ = $TRUE if (defined($_DEBUG_));
294
295         $forceConfig = $TRUE if (defined($forceConfig));
296         $showSessions = $TRUE if (defined($showSessions));
297
298         $enable =~ tr/A-Z/a-z/; $disable =~ tr/A-Z/a-z/;
299         $options =~ tr/a-z/A-Z/ if ($options);
300
301         if ((defined($showSessions) + defined($addDev) + defined($removeDev) +
302              defined($addUser) + defined($enable) + defined($disable) +
303              defined($removeUser) + defined($clearUsers) + defined($assignDev) +
304              defined($releaseDev) + defined($clearDevs) + defined($applyConfig) +
305              defined($clearConfig) + defined($writeConfig) + defined($checkConfig)) > 1) {
306                 print "Please specify only one operation at a time.\n";
307                 usage();
308         }
309
310         $applyConfig = $_DEF_CONFIG_ if (defined($applyConfig) && !$applyConfig);
311         $checkConfig = $_DEF_CONFIG_ if (defined($checkConfig) && !$checkConfig);
312
313         return ($enable, $disable, $addDev, $devPath, $devLun, $removeDev, $addUser, $removeUser,
314                 $clearUsers, $addGroup, $removeGroup, $assignDev, $releaseDev, $clearDevs,
315                 $handler, $group, $options, $blocksize, $applyConfig, $forceConfig,
316                 $clearConfig, $writeConfig, $checkConfig, $showSessions);
317 }
318
319 sub main {
320         my $rc;
321
322         STDOUT->autoflush(1);
323
324         # We need to run as root
325         if ( $> ) {die("This program must run as root.\n");}
326
327         my ($enable, $disable, $addDev, $devPath, $devLun, $removeDev, $addUser, $removeUser,
328             $clearUsers, $addGroup, $removeGroup, $assignDev, $releaseDev, $clearDevs,
329             $handler, $group, $options, $blocksize, $applyConfig, $forceConfig,
330             $clearConfig, $writeConfig, $checkConfig, $showSessions) = getArgs();
331
332         $SCST = new SCST::SCST($_DEBUG_);
333
334         readWorkingConfig();
335
336         SWITCH: {
337                 $applyConfig && do {
338                         if ($forceConfig) {
339                                 $rc = applyConfiguration($applyConfig, $FALSE, $TRUE);
340                                 die("Configuration errors found, aborting.\n") if ($rc);
341
342                                 print "\nConfiguration will apply in 10 seconds, type ctrl-c to abort..\n";
343                                 sleep 10;
344                         }
345
346                         readWorkingConfig();
347                         $rc = applyConfiguration($applyConfig, $forceConfig, $FALSE);
348                         last SWITCH;
349                 };
350                 $checkConfig && do {
351                         $rc = applyConfiguration($checkConfig, $FALSE, $TRUE);
352                         last SWITCH;
353                 };
354                 $writeConfig && do {
355                         $rc = writeConfiguration($writeConfig);
356                         last SWITCH;
357                 };
358                 $showSessions && do {
359                         $rc = showSessions();
360                         last SWITCH;
361                 };
362                 defined($clearConfig) && do {
363                         $rc = clearConfiguration();
364                         last SWITCH;
365                 };
366                 $addDev && do {
367                         $rc = addDevice($handler, $addDev, $devPath, $options, $blocksize);
368                         last SWITCH;
369                 };
370                 $removeDev && do {
371                         $rc = removeDevice($handler, $removeDev);
372                         last SWITCH;
373                 };
374                 $addUser && do {
375                         $rc = addUser($group, $addUser);
376                         last SWITCH;
377                 };
378                 $removeUser && do {
379                         $rc = removeUser($group, $removeUser);
380                         last SWITCH;
381                 };
382                 defined($clearUsers) && do {
383                         $rc = clearUsers($group);
384                         last SWITCH;
385                 };
386                 $addGroup && do {
387                         $rc = addGroup($addGroup);
388                         last SWITCH;
389                 };
390                 $removeGroup && do {
391                         $rc = removeGroup($removeGroup);
392                         last SWITCH;
393                 };
394                 $assignDev && do {
395                         $rc = assignDevice($group, $assignDev, $devLun);
396                         last SWITCH;
397                 };
398                 $releaseDev && do {
399                         $rc = releaseDevice($group, $releaseDev);
400                         last SWITCH;
401                 };
402                 defined($clearDevs) && do {
403                         $rc = clearDevices($group);
404                         last SWITCH;
405                 };
406                 $enable && do {
407                         $enable = unformatTarget($enable);
408                         $rc = enableTarget($enable, $TRUE);
409                         last SWITCH;
410                 };
411                 $disable && do {
412                         $disable = unformatTarget($disable);
413                         $rc = enableTarget($disable, $FALSE);
414                         last SWITCH;
415                 };
416
417                 print "No valid operations specified.\n";
418                 usage();
419                 exit $TRUE;
420         }
421
422         print "All done.\n";
423
424         exit $rc;
425 }
426
427 sub readWorkingConfig {
428         my %empty;
429
430         print "Collecting current configuration.. ";
431
432         $TARGETS  = undef;
433         $DEVICES  = undef;
434         %HANDLERS = ();
435         %GROUPS   = ();
436         %USERS    = ();
437
438         my $eHandlers = $SCST->handlers();
439
440         immediateExit($SCST->errorString());
441
442         foreach my $handler (@{$eHandlers}) {
443                 $HANDLERS{$handler}++; # For quick lookups
444         }
445
446         $TARGETS = targets();
447
448         $DEVICES = $SCST->devices();
449         immediateExit($SCST->errorString());
450
451         my $_eGroups = $SCST->groups();
452         immediateExit($SCST->errorString());
453
454         foreach my $group (@{$_eGroups}) {
455                 $GROUPS{$group}++;
456                 $ASSIGNMENTS{$group} = $SCST->groupDevices($group);
457                 my $eUsers = $SCST->users($group);
458
459                 foreach my $user (@{$eUsers}) {
460                         $USERS{$group}->{$user}++; # For quick lookups
461                 }
462                 $USERS{$group} = \%empty if (!$USERS{$group});
463         }
464
465         print "done.\n\n";
466 }
467
468 sub writeConfiguration {
469         my $file = shift;
470
471         if (-f $file) {
472                 if (!unlink $file) {
473                         print "Failed to save current configuration, specified ".
474                           "file exists and cannot be deleted.\n";
475                         return 1;
476                 }
477         }
478
479         my $io = new IO::File $file, O_CREAT|O_WRONLY;
480
481         if (!$io) {
482                 print "Failed to save configuration to file '$file': $!\n";
483                 return 1;
484         }
485
486         print "Writing current configuration to file '$file'.. ";
487
488         print $io "# Automatically generated by $Version.\n\n";
489
490         # Device information
491         foreach my $handler (sort keys %HANDLERS) {
492                 print $io "[HANDLER ".$_REVERSE_MAP_{$handler}."]\n";
493
494                 if ($SCST->handlerType($handler) == $SCST::SCST::IOTYPE_VIRTUAL) {
495                         print $io "#DEVICE <vdisk name>,<device path>";
496                         if ($handler == $SCST::SCST::VDISK_TYPE) {
497                                 print $io ",<options>,<block size>\n";
498                         } else {
499                                 print $io "\n";
500                         }
501                 } else {
502                         print $io "#DEVICE <H:C:I:L>\n";
503                 }
504
505                 my $devices = $SCST->handlerDevices($handler);
506
507                 immediateExit($SCST->errorString());
508
509                 foreach my $device (sort keys %{$devices}) {
510                         my $options = $$devices{$device}->{'OPTIONS'};
511
512                         $options =~ s/\,/\|/g;
513
514                         print $io "DEVICE $device,".$$devices{$device}->{'PATH'};
515                         print $io ",$options";
516                         print $io ",".$$devices{$device}->{'BLOCKSIZE'};
517                         print $io "\n";
518                 }
519
520                 print $io "\n";
521         }
522
523         # User configuration
524         foreach my $group (sort keys %USERS) {
525                 print $io "[GROUP $group]\n";
526                 print $io "#USER <user wwn>\n";
527
528                 foreach my $user (keys %{$USERS{$group}}) {
529                         print $io "USER $user\n";
530                 }
531
532                 print $io "\n";
533         }
534
535         # Assignments configuration
536         foreach my $group (sort keys %ASSIGNMENTS) {
537                 print $io "[ASSIGNMENT $group]\n";
538                 print $io "#DEVICE <device name>,<lun>\n";
539
540                 my $pointer = $ASSIGNMENTS{$group};
541                 foreach my $device (sort keys %{$pointer}) {
542                         print $io "DEVICE $device,".$$pointer{$device}."\n";
543                 }
544
545                 print $io "\n";
546         }
547
548         # Targets configuration
549         foreach my $type ('enable', 'disable') {
550                 print $io "[TARGETS $type]\n";
551                 print $io "#HOST <wwn identifier>\n";
552
553                 foreach my $target (sort keys %{$TARGETS}) {
554                         if ((($type eq 'enable') && $$TARGETS{$target}->{'enabled'}) ||
555                             (($type eq 'disable') && !$$TARGETS{$target}->{'enabled'})) {
556                                 my $f_target = formatTarget($target);
557                                 print $io "HOST $f_target\n" if (!$$TARGETS{$target}->{'duplicate'});
558                         }
559                 }
560
561                 print $io "\n";
562         }
563
564         print "done\n";
565
566         close $io;
567
568         return 0;
569 }
570
571 sub applyConfiguration {
572         my $confile = shift;
573         my $force = shift;
574         my $check = shift;
575         my $config = readConfig($confile);
576         my $errs;
577         my $changes = 0;
578
579         my %used_devs;
580         my %used_users;
581         my %used_assignments;
582         my %empty;
583
584         # Cache device/handler configuration
585         foreach my $entry (keys %{$$config{'HANDLER'}}) {
586                 foreach my $device (@{$$config{'HANDLER'}->{$entry}->{'DEVICE'}}) {
587                         my($vname, undef) = split(/\,/, $device, 2);
588                         $vname = cleanupString($vname);
589                         $used_devs{$vname} = $entry;
590                 }
591         }
592
593         # Cache user/group configuration
594         foreach my $group (keys %{$$config{'GROUP'}}) {
595                 foreach my $user (@{$$config{'GROUP'}->{$group}->{'USER'}}) {
596                         $used_users{$group}->{$user}++;
597                 }
598                 $used_users{$group} = \%empty if (!$used_users{$group});
599         }
600
601         # Cache device association configuration
602         foreach my $group (keys %{$$config{'ASSIGNMENT'}}) {
603                 foreach my $device (@{$$config{'ASSIGNMENT'}->{$group}->{'DEVICE'}}) {
604                         my($vname, $lun) = split(/\,/, $device);
605                         $vname = cleanupString($vname);
606                         $used_assignments{$group}->{$vname} = $lun;
607                 }
608         }
609
610         # If -ForceConfig is used, check for configurations which we've deleted but are still active.
611         if ($force || $check) {
612                 # Associations
613                 foreach my $group (sort keys %ASSIGNMENTS) {
614                         if (!defined($used_assignments{$group}) && (keys %{$ASSIGNMENTS{$group}})) {
615                                 print "\t-> WARNING: Group '$group' has no associations in saved configuration";
616
617                                 if (!$check) {
618                                         print ", clearing all associations.\n";
619                                         if (clearDevices($group)) {
620                                                 $errs++;
621                                         } else {
622                                                 $changes++;
623                                         }
624                                 } else {
625                                         print ".\n";
626                                         $changes++;
627                                 }
628                         } else {
629                                 my $_assignments = $ASSIGNMENTS{$group};
630
631                                 foreach my $device (sort keys %{$_assignments}) {
632                                         if (!defined($used_assignments{$group}->{$device}) ||
633                                            ($$_assignments{$device} != $used_assignments{$group}->{$device})) {
634                                                 if ($$_assignments{$device} != $used_assignments{$group}->{$device}) {
635                                                         print "\t-> WARNING: Device '$device' assigned to group '$group' is at LUN ".
636                                                           $used_assignments{$group}->{$device}.
637                                                           " whereas working configuration reflects LUN ".$$_assignments{$device}; 
638                                                 } else {
639                                                         print "\t-> WARNING: Device '$device' is not associated with group ".
640                                                           "'$group' in saved configuration";
641                                                 }
642
643                                                 if (!$check) {
644                                                         print ", releasing.\n";
645                                                         if (releaseDevice($group, $device)) {
646                                                                 $errs++;
647                                                         } else {
648                                                                 $changes++;
649                                                         }
650                                                 } else {
651                                                         print ".\n";
652                                                         $changes++;
653                                                 }
654                                         }
655                                 }
656                         }
657                 }
658
659                 # Users & Groups
660                 foreach my $group (sort keys %USERS) {
661                         next if ($group eq $_DEFAULT_GROUP_);
662                         if (!defined($used_users{$group})) {
663                                 print "\t-> WARNING: Group '$group' does not exist in saved configuration";
664
665                                 if (!$check) {
666                                         print ", removing.\n";
667                                         if (clearUsers($group)) {
668                                                 $errs++;
669                                         } else {
670                                                 $changes++;
671                                         }
672
673                                         if (removeGroup($group)) {
674                                                 $errs++;
675                                         } else {
676                                                 $changes++;
677                                         }
678                                 } else {
679                                         print ".\n";
680                                         $changes++;
681                                 }
682                         } else {
683                                 foreach my $user (sort keys %{$USERS{$group}}) {
684                                         if (!defined($used_users{$group}->{$user})) {
685                                                 print "\t-> WARNING: User '$user' is not defined as part of group '$group' ".
686                                                   "in saved configuration";
687
688                                                 if (!$check) {
689                                                         print ", removing.\n";
690                                                         if (removeUser($group, $user)) {
691                                                                 $errs++;
692                                                         } else {
693                                                                 $changes++;
694                                                         }
695                                                 } else {
696                                                         print ".\n";
697                                                         $changes++;
698                                                 }
699                                         }
700                                 }
701                         }
702                 }
703
704                 # Devices
705                 foreach my $device (sort keys %{$DEVICES}) {
706                         if ($$DEVICES{$device} && !defined($used_devs{$device})) {
707                                 # Device gone, but is it still assigned to a group?
708                                 my $isAssigned = $FALSE;
709                                 foreach my $group (sort keys %used_assignments) {
710                                         if (defined($used_assignments{$group}->{$device})) {
711                                                 print "\t-> WARNING: Device '$device' is not defined in saved configuration, ".
712                                                   "however, it is still assigned to group '$group'! Ignoring removal.\n";
713                                                 $isAssigned = $TRUE;
714                                         }
715                                 }
716
717                                 if (!$isAssigned && ($SCST->handlerType($$DEVICES{$device}) == $SCST::SCST::IOTYPE_VIRTUAL)) {
718                                         print "\t-> WARNING: Device '$device' is not defined in saved configuration";
719
720                                         if (!$check) {
721                                                 print ", removing.\n";
722                                                 if (removeDevice($_REVERSE_MAP_{$$DEVICES{$device}}, $device)) {
723                                                         $errs++;
724                                                 } else {
725                                                         $changes++;
726                                                 }
727                                         } else {
728                                                 print ".\n";
729                                                 $changes++;
730                                         }
731                                 }
732                         } else {
733                                 # Handler change
734                                 if ($_HANDLER_MAP_{$used_devs{$device}} != $$DEVICES{$device}) {
735                                         my $handler = $used_devs{$device};
736
737                                         if ($HANDLERS{$_HANDLER_MAP_{$handler}}) {
738                                                 print "\t-> WARNING: Device '$device' changes handler to '$handler'";
739
740                                                 if (!$check) {
741                                                         print ", changing.\n";
742                                                         if ($SCST->assignDeviceToHandler($device,
743                                                                                          $_HANDLER_MAP_{$handler})) {
744                                                                 $errs++;
745                                                         } else {
746                                                                 $changes++;
747                                                         }
748                                                 } else {
749                                                         print ".\n";
750                                                         $changes++;
751                                                 }
752                                         }
753                                 }
754                         }
755                 }
756         }
757
758         print "Applying configuration additions..\n" if (!$check);
759         print "\n";
760
761         readWorkingConfig() if ($force);
762
763         foreach my $_handler (sort keys %{$$config{'HANDLER'}}) {
764                 if (!$HANDLERS{$_HANDLER_MAP_{$_handler}}) {
765                         print "\t-> WARNING: Handler '$_handler' does not exist.\n";
766                         $errs += 1;
767                         next;
768                 }
769
770                 foreach my $device (@{$$config{'HANDLER'}->{$_handler}->{'DEVICE'}}) {
771                         my($vname, $path, $options, $blocksize) = split(/\,/, $device);
772                         $path = cleanupString($path);
773                         $options =~ s/\s+//g;
774
775                         if (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} == $$DEVICES{$vname})) {
776                                 next;
777                         } elsif (defined($$DEVICES{$vname}) && ($_HANDLER_MAP_{$_handler} != $$DEVICES{$vname})) {
778                                 if ($HANDLERS{$_HANDLER_MAP_{$_handler}}) {
779                                         print "\t-> WARNING: Device '$vname' changes handler from '".
780                                           $_REVERSE_MAP_{$$DEVICES{$vname}}."' to '$_handler'.\n".
781                                           "\t   Use -ForceConfig to change device handler.\n" if (!$force && !$check);
782                                 }
783                                 next;
784                         }
785
786                         if ($check) {
787                                 print "\t-> New device '$_handler:$vname' at path '$path', options '$options', ".
788                                   "blocksize $blocksize.\n";
789                                 $$DEVICES{$vname} = $_HANDLER_MAP_{$_handler};
790                                 $changes++;
791                         } else {
792                                 if (addDevice($_handler, $vname, $path, $options, $blocksize)) {
793                                         $errs++;
794                                 } else {
795                                         $changes++;
796                                 }
797                         }
798                 }
799         }
800
801         # Create new groups and add users..
802         foreach my $group (keys %used_users) {
803                 if (!defined($USERS{$group})) {
804                         if ($check) {
805                                 print "\t-> New group definition '$group.'\n";
806                                 $GROUPS{$group}++;
807                                 $changes++;
808                         } else {
809                                 if (addGroup($group)) {
810                                         $errs++;
811                                 } else {
812                                         $changes++;
813                                 }
814                         }
815                 }
816
817                 foreach my $user (keys %{$used_users{$group}}) {
818                         if (!defined($USERS{$group}->{$user})) {
819                                 if ($check) {
820                                         print "\t-> New user definition '$user' for group '$group'.\n";
821                                         $USERS{$group}->{$user}++;
822                                         $changes++;
823                                 } else {
824                                         if (addUser($group, $user)) {
825                                                 $errs++;
826                                         } else {
827                                                 $changes++;
828                                         }
829                                 }
830                         }
831                 }
832         }
833
834         # Assign new devices to groups..
835         foreach my $group (keys %used_assignments) {
836                 if (!defined($GROUPS{$group})) {
837                         # Looks like we're lacking a group. We'll create an empty one
838
839                         print "\t-> WARNING: Auto-creating an empty group '$group' since none was configured.\n";
840
841                         if (addGroup($group)) {
842                                 $errs++;
843                         } else {
844                                 $changes++;
845                         }
846                 }
847
848                 if (!defined($GROUPS{$group})) {
849                         print "\t-> WARNING: Unable to assign to non-existant group '$group'.\n";
850                         $errs += 1;
851                         next;
852                 }
853
854                 foreach my $vname (keys %{$used_assignments{$group}}) {
855                         my $lun = $used_assignments{$group}->{$vname};
856                         my $_assignments = $ASSIGNMENTS{$group};
857
858                         if (defined($$_assignments{$vname}) && ($$_assignments{$vname} == $lun)) {
859                                 next;
860                         } elsif (defined($$_assignments{$vname}) && ($$_assignments{$vname} != $lun)) {
861                                 print "\t-> Device '$vname' assigned to group '$group' is at LUN ".$$_assignments{$vname}.
862                                   ", whereas the working configuration reflects LUN $lun.\n".
863                                   "\t   Use -ForceConfig to force this LUN change.\n" if (!$force && !$check);
864                         } else {
865                                 if ($check) {
866                                         $lun = 'auto' if (!defined($lun));
867                                         print "\t-> New device assignment for '$vname' to group '$group' at LUN $lun.\n";
868                                         $changes++;
869                                 } else {
870                                         if (assignDevice($group, $vname, $lun)) {
871                                                 $errs++;
872                                         } else {
873                                                 $changes++;
874                                         }
875                                 }
876                         }
877                 }
878         }
879
880         # Enable/Disable configured targets
881         foreach my $type (keys %{$$config{'TARGETS'}}) {
882                 my $enable;
883
884                 if ($type eq 'enable') {
885                         $enable = $TRUE;
886                 } elsif ($type eq 'disable') {
887                         $enable = $FALSE;
888                 } else {
889                         print "\t-> WARNING: Ignoring invalid TARGETS specifier '$type'. ".
890                           "Should be one of enable,disable.\n";
891                         next;
892                 }
893
894                 foreach my $target (@{$$config{'TARGETS'}->{$type}->{'HOST'}}) {
895                         my $i_target = unformatTarget($target);
896
897                         if (!defined($$TARGETS{$i_target})) {
898                                 print "\t-> WARNING: Target '$target' not found on system.\n";
899                                 $errs += 1;
900                                 next;
901                         }
902
903                         next if ($enable == targetEnabled($i_target));
904
905                         if (!$enable && targetEnabled($target)) {
906                                 if ($force || $check) {
907                                         print "\t-> WARNING: Target mode for '$target' is currently enabled, ".
908                                           "however configuration file wants it disabled";
909
910                                         if (!$check) {
911                                                 print ", disabling.\n";
912                                                 if (enableTarget($target, $enable)) {
913                                                         $errs++;
914                                                 } else {
915                                                         $changes++;
916                                                 }
917                                         } else {
918                                                 print ".\n";
919                                                 $changes++;
920                                         }
921                                 }
922                         } else {
923                                 print "\t-> Target '$target' is enabled in configuration file, ".
924                                   "however is currently disabled";
925
926                                 if (!$check) {
927                                         print ", enabling.\n";
928                                         if (enableTarget($target, $enable)) {
929                                                 $errs++;
930                                         } else {
931                                                 $changes++;
932                                         }
933                                 } else {
934                                         print ".\n";
935                                         $changes++;
936                                 }
937                         }
938                 }
939         }
940
941         print "\nEncountered $errs error(s) while processing.\n" if ($errs);
942
943         if ($check) {
944                 print "Configuration checked, $changes difference(s) found with working configuration.\n";
945         } else {
946                 $changes = 0 if ($_DEBUG_);
947                 print "Configuration applied, $changes changes made.\n";
948         }
949
950         return $TRUE if ($errs);
951         return $FALSE;
952 }
953
954 sub clearConfiguration {
955         my $errs;
956
957         print "WARNING: This removes ALL applied SCST configuration and may result in data loss!\n";
958         print "If this is not what you intend, press ctrl-c now. Waiting 10 seconds.\n\n";
959         sleep 10;
960
961         print "\nRemoving all user and groups:\n\n";
962         foreach my $group (keys %GROUPS) {
963                 $errs += removeGroup($group) if ($group ne $_DEFAULT_GROUP_);
964         }
965
966         print "\nRemoving all handler devices:\n\n";
967         foreach my $device (keys %{$DEVICES}) {
968                 next if (!$$DEVICES{$device});
969                 next if ($SCST->handlerType($$DEVICES{$device}) != $SCST::SCST::IOTYPE_VIRTUAL);
970                 $errs += removeDevice($_REVERSE_MAP_{$$DEVICES{$device}}, $device);
971         }
972
973         print "\nEncountered $errs error(s) while processing.\n" if ($errs);
974         print "\nConfiguration cleared.\n";
975
976         return $TRUE if ($errs);
977         return $FALSE;
978 }
979
980 sub showSessions {
981         my $sessions = $SCST->sessions();
982         immediateExit($SCST->errorString());
983
984         print "\n\tTarget Name\tInitiator Name\t\t\tGroup Name\t\tCommand Count\n";
985
986         foreach my $target (keys %{$sessions}) {
987                 foreach my $group (keys %{$$sessions{$target}}) {
988                         foreach my $user (keys %{$$sessions{$target}->{$group}}) {
989                                 my $commands = $$sessions{$target}->{$group}->{$user};
990
991                                 print "\t$target\t$user\t\t$group\t\t$commands\n";
992                         }
993                 }
994         }
995
996         print "\n";
997
998         return $FALSE;
999 }
1000
1001 sub addDevice {
1002         my $handler = shift;
1003         my $device = shift;
1004         my $path = shift;
1005         my $options = shift;
1006         my $blocksize = shift;
1007
1008         my $_handler = $_HANDLER_MAP_{$handler};
1009         my $htype = $SCST->handlerType($_handler);
1010
1011         if (!$htype) {
1012                 print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
1013                 return $TRUE;
1014         }
1015
1016         if ($htype != $SCST::SCST::IOTYPE_VIRTUAL) {
1017                 my $typeString = $_HANDLER_TYPE_MAP_{$htype};
1018                 my $validType = $_HANDLER_TYPE_MAP_{$SCST::SCST::IOTYPE_VIRTUAL};
1019                 print "WARNING: Handler $handler of type $typeString is incapable of ".
1020                   "opening/closing devices. Valid handlers are:\n".
1021                   validHandlerTypes($SCST::SCST::IOTYPE_VIRTUAL)."\n";
1022                 return $TRUE;
1023         }
1024
1025         if (defined($$DEVICES{$device})) {
1026                 print "WARNING: Device '$device' already defined.\n";
1027                 return $TRUE;
1028         }
1029
1030         print "\t-> Opening virtual device '$device' at path '$path' using handler '$handler'..\n";
1031
1032         if ($SCST->openDevice($_handler, $device, $path, $options, $blocksize)) {
1033                 print "WARNING: Failed to open virtual device '$device' at path '$path': ".
1034                   $SCST->errorString()."\n";
1035                 return $TRUE;
1036         }
1037
1038         $$DEVICES{$device} = $_handler;
1039
1040         return $FALSE;
1041 }
1042
1043 sub removeDevice {
1044         my $handler = shift;
1045         my $device = shift;
1046
1047         my $_handler = $_HANDLER_MAP_{$handler};
1048         my $htype = $SCST->handlerType($_handler);
1049
1050         if (!$htype) {
1051                 print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
1052                 return $TRUE;
1053         }
1054
1055         if ($htype != $SCST::SCST::IOTYPE_VIRTUAL) {
1056                 my $typeString = $_HANDLER_TYPE_MAP_{$htype};
1057                 my $validType = $_HANDLER_TYPE_MAP_{$SCST::SCST::IOTYPE_VIRTUAL};
1058                 print "WARNING: Handler $handler of type $typeString is incapable of ".
1059                   "opening/closing devices. Valid handlers are:\n".
1060                   validHandlerTypes($SCST::SCST::IOTYPE_VIRTUAL)."\n";
1061                 return $TRUE;
1062         }
1063
1064         if (!defined($$DEVICES{$device})) {
1065                 print "WARNING: Device '$device' not defined.\n";
1066                 return $TRUE;
1067         }
1068
1069         print "\t-> Closing virtual device '$device'..\n";
1070
1071         if ($SCST->closeDevice($_handler, $device)) {
1072                 print "WARNING: Failed to close virtual device '$device': ".
1073                   $SCST->errorString()."\n";
1074                 return $TRUE;
1075         }
1076
1077         undef $$DEVICES{$device};
1078
1079         return $FALSE;
1080 }
1081
1082 sub addGroup {
1083         my $group = shift;
1084
1085         if (defined($GROUPS{$group})) {
1086                 print "WARNING: Group '$group' already exists.\n";
1087                 return $TRUE;
1088         }
1089
1090         print "\t-> Creating security group '$group'..\n";
1091
1092         if ($SCST->addGroup($group)) {
1093                 print "WARNING: Failed to create security group '$group': ".
1094                   $SCST->errorString()."\n";
1095                 return $TRUE;
1096         }
1097
1098         $GROUPS{$group}++;
1099
1100         return $FALSE;
1101 }
1102
1103 sub removeGroup {
1104         my $group = shift;
1105
1106         return $FALSE if ($group eq $_DEFAULT_GROUP_);
1107
1108         if (!defined($GROUPS{$group})) {
1109                 print "WARNING: Group '$group' does not exist.\n";
1110                 return $TRUE;
1111         }
1112
1113         print "\t-> Removing security group '$group'..\n";
1114
1115         if ($SCST->removeGroup($group)) {
1116                 print "WARNING: Failed to remove security group '$group': ".
1117                   $SCST->errorString()."\n";
1118                 return $TRUE;
1119         }
1120
1121         undef $GROUPS{$group};
1122
1123         return $FALSE;
1124 }
1125
1126 sub addUser {
1127         my $group = shift;
1128         my $user = shift;
1129
1130         if (!defined($GROUPS{$group})) {
1131                 print "WARNING: Failed to add user '$user' to group '$group', group does not exist.\n";
1132                 return $TRUE;
1133         }
1134
1135         if (defined($USERS{$group}->{$user})) {
1136                 print "WARNING: User '$user' already exists in security group '$group'.\n";
1137                 return $TRUE;
1138         }
1139
1140         print "\t-> Adding user '$user' to security group '$group'..\n";
1141
1142         if ($SCST->addUser($user, $group)) {
1143                 print "WARNING: Failed to add user '$user' to security group '$group': ".
1144                   $SCST->errorString()."\n";
1145                 return $TRUE;
1146         }
1147
1148         $USERS{$group}->{$user}++;
1149
1150         return $FALSE;
1151 }
1152
1153 sub removeUser {
1154         my $group = shift;
1155         my $user = shift;
1156
1157         if (!defined($GROUPS{$group})) {
1158                 print "WARNING: Failed to remove user '$user' from group '$group', group does not exist.\n";
1159                 return $TRUE;
1160         }
1161
1162         if (!defined($USERS{$group}->{$user})) {
1163                 print "WARNING: User '$user' doesn\'t exist in security group '$group'.\n";
1164                 return $TRUE;
1165         }
1166
1167         print "\t-> Removing user '$user' from security group '$group'..\n";
1168
1169         if ($SCST->removeUser($user, $group)) {
1170                 print "WARNING: Failed to remove user '$user' to security group '$group': ".
1171                   $SCST->errorString()."\n";
1172                 return $TRUE;
1173         }
1174
1175         undef $USERS{$group}->{$user};
1176
1177         return $FALSE;
1178 }
1179
1180 sub clearUsers {
1181         my $group = shift;
1182
1183         if (!defined($GROUPS{$group})) {
1184                 print "WARNING: Failed to clear users from group '$group', group does not exist.\n";
1185                 return $TRUE;
1186         }
1187
1188         print "\t-> Clearing users from security group '$group'..\n";
1189
1190         if ($SCST->clearUsers($group)) {
1191                 print "WARNING: Failed to clear users from security group '$group': ".
1192                   $SCST->errorString()."\n";
1193                 return $TRUE;
1194         }
1195
1196         undef $USERS{$group};
1197
1198         return $FALSE;
1199 }
1200
1201 sub assignDevice {
1202         my $group = shift;
1203         my $device = shift;
1204         my $lun = shift;
1205         my %allLuns;
1206
1207         # Put luns into something easier to parse..
1208         foreach my $_group (keys %ASSIGNMENTS) {
1209                 my $_gAssigns = $ASSIGNMENTS{$_group};
1210
1211                 foreach my $_device (keys %{$_gAssigns}) {
1212                         @{$allLuns{$_group}}[$$_gAssigns{$_device}] = $_device;
1213                 }
1214         }
1215
1216         # Use the next available LUN if none specified
1217         if ($lun !~ /\d+/) {
1218                 $lun = ($#{$allLuns{$group}} + 1);
1219                 if ($lun > $_MAX_LUNS_) {
1220                         print "ERROR: Unable to use next available LUN of $lun, lun out of range.\n";
1221                         return $TRUE;
1222                 }
1223
1224                 print "\t-> Device '$device': Using next available LUN of $lun for group '$group'.\n";
1225         }
1226                         
1227         if (($lun < 0) || ($lun > $_MAX_LUNS_)) {
1228                 print "ERROR: Unable to assign device '$device', lun '$lun' is out of range.\n";
1229                 return $TRUE;
1230         }
1231
1232         if (!defined($$DEVICES{$device})) {
1233                 print "WARNING: Unable to assign non-existant device '$device' to group '$group'.\n";
1234                 return $TRUE;
1235         }
1236
1237         if (@{$allLuns{$group}}[$lun]) {
1238                 print "ERROR: Device '$device': Lun '$lun' is already assigned to device '".@{$allLuns{$group}}[$lun]."'.\n";
1239                 return $TRUE;
1240         }
1241
1242         print "\t-> Assign virtual device '$device' to group '$group' at LUN '$lun'..\n";
1243
1244         if ($SCST->assignDeviceToGroup($device, $group, $lun)) {
1245                 print "WARNING: Failed to assign device '$device' to group '$group': ".
1246                   $SCST->errorString()."\n";
1247                 return $TRUE;
1248         }
1249
1250         if (!defined($ASSIGNMENTS{$group})) {
1251                 my %assignments_t;
1252                 $ASSIGNMENTS{$group} = \%assignments_t;
1253         }
1254
1255         my $_assignments = $ASSIGNMENTS{$group};
1256
1257         $$_assignments{$device} = $lun; 
1258
1259         return $FALSE;
1260 }
1261
1262 sub releaseDevice {
1263         my $group = shift;
1264         my $device = shift;
1265
1266         if (!defined($GROUPS{$group})) {
1267                 print "WARNING: Failed to release device '$device' from group '$group', group does not exist.\n";
1268                 return $TRUE;
1269         }
1270
1271         if (!defined($$DEVICES{$device})) {
1272                 print "WARNING: Failed to release device '$device', device not defined.\n";
1273                 return $TRUE;
1274         }
1275
1276         print "\t-> Release virtual device '$device' from group '$group'..\n";
1277
1278         if ($SCST->removeDeviceFromGroup($device, $group)) {
1279                 print "WARNING: Failed to release device '$device' from group '$group': ".
1280                   $SCST->errorString()."\n";
1281                 return $TRUE;
1282         }
1283
1284         my $_assignments = $ASSIGNMENTS{$group};
1285
1286         undef $$_assignments{$device};
1287
1288         return $FALSE;
1289 }
1290
1291 sub clearDevices {
1292         my $group = shift;
1293
1294         if (!defined($GROUPS{$group})) {
1295                 print "WARNING: Failed to clear devices from group '$group', group does not exist.\n";
1296                 return $TRUE;
1297         }
1298
1299         print "\t-> Clear virtual devices from group '$group'..\n";
1300
1301         if ($SCST->clearGroupDevices($group)) {
1302                 print "WARNING: Failed to clear devices from group '$group': ".
1303                   $SCST->errorString()."\n";
1304                 return $TRUE;
1305         }
1306
1307         undef $ASSIGNMENTS{$group};
1308
1309         return $FALSE;
1310 }
1311
1312 sub targets {
1313         my %targets;
1314         my %fcards;
1315
1316         my $root = new IO::Dir $_FC_CLASS_ if (-d $_FC_CLASS_);
1317
1318         if ($root) {
1319                 while (my $entry = $root->read()) {
1320                         next if (($entry eq '.') || ($entry eq '..'));
1321
1322                         my $io = new IO::File "$_FC_CLASS_/$entry/port_name", O_RDONLY;
1323
1324                         if ($io) {
1325                                 my $wwn = <$io>;
1326                                 chomp $wwn;
1327                                 close $io;
1328
1329                                 $fcards{$entry} = $wwn;
1330                         }
1331                 }
1332         }
1333
1334         $root = new IO::Dir $_SCSI_CLASS_ if (-d $_SCSI_CLASS_);
1335
1336         if ($root) {
1337                 while (my $entry = $root->read()) {
1338                         next if (($entry eq '.') || ($entry eq '..'));
1339
1340                         my $io = new IO::File "$_SCSI_CLASS_/$entry/target_mode_enabled", O_RDONLY;
1341
1342                         if ($io) {
1343                                 my $enabled = <$io>;
1344                                 chomp $enabled;
1345                                 close $io;
1346
1347                                 $targets{$entry}->{'path'} = "$_SCSI_CLASS_/$entry/target_mode_enabled";
1348                                 $targets{$entry}->{'enabled'} = $enabled;
1349                                 $targets{$entry}->{'qla_isp'} = $FALSE;
1350
1351                                 if ($fcards{$entry}) {
1352                                         $targets{$fcards{$entry}}->{'enabled'} = $enabled;
1353                                         $targets{$fcards{$entry}}->{'path'} =
1354                                           "$_SCSI_CLASS_/$entry/target_mode_enabled";
1355                                         $targets{$entry}->{'duplicate'} = $TRUE;
1356                                 } else {
1357                                         $targets{$entry}->{'duplicate'} = $FALSE;
1358                                 }
1359                         }
1360                 }
1361         }
1362
1363         $root = new IO::Dir $_SCSI_ISP_ if (-d $_SCSI_ISP_);
1364
1365         if ($root) {
1366                 while (my $entry = $root->read()) {
1367                         next if (($entry eq '.') || ($entry eq '..'));
1368
1369                         local $/;
1370                         my $io = new IO::File "$_SCSI_ISP_/$entry", O_RDONLY;
1371
1372                         if ($io) {
1373                                 my $wwn;
1374                                 my $fstr;
1375                                 my $enabled2;
1376
1377                                 $fstr = <$io>;
1378                                 close $io;
1379
1380                                 ($wwn) = ($fstr =~ '.*?Port WWN +([^\ ]+) .*');
1381                                 $fcards{$entry} = $wwn;
1382
1383                                 $io = new IO::File "$_SCSITGT_QLAISP_/$entry", O_RDONLY;
1384                                 if ($io) {
1385                                         $fstr = <$io>;
1386                                         close $io;
1387
1388                                         ($enabled2) = ($fstr =~ '[^\n]+\n *\d *: *(\d)');
1389                                         $targets{$entry}->{'path'} = "$_SCSITGT_QLAISP_/$entry";
1390                                         $targets{$entry}->{'enabled'} = $enabled2;
1391                                         $targets{$entry}->{'qla_isp'} = $TRUE;
1392
1393                                         if ($fcards{$entry}) {
1394                                                 $targets{$fcards{$entry}}->{'enabled'} = $enabled2;
1395                                                 $targets{$fcards{$entry}}->{'path'} = "$_SCSITGT_QLAISP_/$entry";
1396                                                 $targets{$fcards{$entry}}->{'qla_isp'} = $TRUE;
1397                                                 $targets{$entry}->{'duplicate'} = $TRUE;
1398                                         } else {
1399                                                 $targets{$entry}->{'duplicate'} = $FALSE;
1400                                         }
1401                                 }
1402                         }
1403                 }
1404         }
1405
1406         return \%targets;
1407 }
1408
1409 sub targetEnabled {
1410         my $target = shift;
1411
1412         return undef if (!defined($$TARGETS{$target}));
1413         return $$TARGETS{$target}->{'enabled'};
1414 }
1415
1416 sub enableTarget {
1417         my $target = shift;
1418         my $enable = shift;
1419
1420         $target = unformatTarget($target);
1421
1422         return undef if (!defined($$TARGETS{$target}));
1423
1424         my $io = new IO::File $$TARGETS{$target}->{'path'}, O_WRONLY;
1425         return $TRUE if (!$io);
1426
1427         print $enable ? "\t-> Enabling" : "\t-> Disabling";
1428         print " target mode for SCST host '$target'.\n";
1429
1430         if ($_DEBUG_) {
1431                 print "DBG($$): ".$$TARGETS{$target}->{'path'}." -> $enable\n\n";
1432         } else {
1433                 if ($$TARGETS{$target}->{'qla_isp'} == $FALSE) {
1434                         print $io $enable;
1435                 } else {
1436                         print $io $enable ? "enable all" : "disable all";
1437                 }
1438         }
1439
1440         close $io;
1441
1442         $$TARGETS{$target}->{'enabled'} = $enable;
1443
1444         return $FALSE;
1445 }
1446
1447 sub readConfig {
1448         my $confile = shift;
1449         my %config;
1450         my $section;
1451         my $last_section;
1452         my $arg;
1453         my $last_arg;
1454         my %empty;
1455
1456         my $io = new IO::File $confile, O_RDONLY;
1457
1458         die("FATAL: Unable to open specified configuration file $confile: $!\n") if (!$io);
1459
1460         while (my $line = <$io>) {
1461                 ($line, undef) = split(/\#/, $line, 2);
1462                 $line = cleanupString($line);
1463
1464                 if ($line =~ /^\[(.*)\]$/) {
1465                         ($section, $arg) = split(/\s+/, $1, 2);
1466
1467                         if ($last_arg && ($last_section ne $section) &&
1468                             !defined($config{$last_section}->{$last_arg})) {
1469                                 $config{$last_section}->{$last_arg} = \%empty;
1470                         }   
1471
1472                         $last_arg = $arg;
1473                         $last_section = $section;
1474                 } elsif ($section && $arg && $line) {
1475                         my($parameter, $value) = split(/\s+/, $line, 2);
1476
1477                         push @{$config{$section}->{$arg}->{$parameter}}, $value;
1478                 }
1479         }
1480
1481         close $io;
1482
1483         return \%config;
1484 }
1485
1486 sub cleanupString {
1487         my $string = shift;
1488
1489         $string =~ s/^\s+//;
1490         $string =~ s/\s+$//;
1491
1492         return $string;
1493 }
1494
1495 sub formatTarget {
1496         my $target = shift;
1497
1498         if ($target =~ /^0x/) {
1499                 $target =~ s/^0x//;
1500                 my($o1, $o2, $o3, $o4, $o5, $o6, $o7, $o8) = unpack("A2A2A2A2A2A2A2A2", $target);
1501                 $target = "$o1:$o2:$o3:$o4:$o5:$o6:$o7:$o8";
1502         }
1503
1504         $target =~ tr/A-Z/a-z/;
1505
1506         return $target;
1507 }
1508
1509 sub unformatTarget {
1510         my $target = shift;
1511
1512         if ($target =~ /^.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}\:.{2}/) {
1513                 $target =~ s/\://g;
1514                 $target = "0x$target";
1515         }
1516
1517         $target =~ tr/A-Z/a-z/;
1518
1519         return $target;
1520 }
1521
1522 sub validHandlerTypes {
1523         my $type = shift;
1524         my $buffer = "\n";
1525
1526         foreach my $handler (keys %_REVERSE_MAP_) {
1527                 $buffer .= "\t".$_REVERSE_MAP_{$handler}."\n" if ($SCST->handlerType($handler) == $type);
1528         }
1529
1530         return $buffer;
1531 }
1532
1533 # If we have an unread error from SCST, exit immediately
1534 sub immediateExit {
1535         my $error = shift;
1536
1537         return if (!$error);
1538
1539         print "\n\nFATAL: Received the following error:\n\n\t";
1540         print "$error\n\n";
1541
1542         exit 1;
1543 }
1544
1545 # Hey! Stop that!
1546 sub commitSuicide {
1547         print "\n\nAborting immediately.\n";
1548         exit 1;
1549 }