3 # Author: Mark R. Buechler
4 # Copyright (c) 2005, 2006 Mark R. Buechler
15 my $_SCST_DIR_ = '/proc/scsi_tgt';
16 my $_SCST_IO_ = $_SCST_DIR_.'/scsi_tgt';
17 my $_SCST_CDROM_IO_ = $_SCST_DIR_.'/dev_cdrom/dev_cdrom';
18 my $_SCST_CHANGER_IO_ = $_SCST_DIR_.'/dev_changer/dev_changer';
19 my $_SCST_DISK_IO_ = $_SCST_DIR_.'/dev_disk/dev_disk';
20 my $_SCST_DISK_FILE_IO_ = $_SCST_DIR_.'/disk_fileio/disk_fileio';
21 my $_SCST_CDROM_FILE_IO_ = $_SCST_DIR_.'/cdrom_fileio/cdrom_fileio';
22 my $_SCST_DISKP_IO_ = $_SCST_DIR_.'/dev_disk_perf/dev_disk_perf';
23 my $_SCST_MODISK_IO_ = $_SCST_DIR_.'/dev_modisk/dev_modisk';
24 my $_SCST_MODISKP_IO_ = $_SCST_DIR_.'/dev_modisk_perf/dev_modisk_perf';
25 my $_SCST_TAPE_IO_ = $_SCST_DIR_.'/dev_tape/dev_tape';
26 my $_SCST_TAPEP_IO_ = $_SCST_DIR_.'/dev_tape_perf/dev_tape_perf';
27 my $_SCST_GROUPS_DIR_ = $_SCST_DIR_.'/groups';
28 my $_SCST_SGV_STATS_ = $_SCST_DIR_.'/sgv';
29 my $_SCST_SESSIONS_ = $_SCST_DIR_.'/sessions';
30 my $_SCST_VERSION_IO_ = $_SCST_DIR_.'/version';
32 my $_SCST_USERS_IO_ = 'names';
33 my $_SCST_DEVICES_IO_ = 'devices';
35 my @_AVAILABLE_OPTIONS_ = ('WRITE_THROUGH', 'O_DIRECT', 'READ_ONLY', 'NULLIO', 'NV_CACHE');
37 use vars qw(@ISA @EXPORT $VERSION $CDROM_TYPE $CHANGER_TYPE $DISK_TYPE $DISKFILE_TYPE
38 $CDROMFILE_TYPE $DISKPERF_TYPE $MODISK_TYPE $MODISKPERF_TYPE $TAPE_TYPE
54 my $_SCST_MIN_MAJOR_ = 0;
55 my $_SCST_MIN_MINOR_ = 9;
56 my $_SCST_MIN_RELEASE_ = 5;
58 my %_IO_MAP_ = ($CDROM_TYPE => $_SCST_CDROM_IO_,
59 $CHANGER_TYPE => $_SCST_CHANGER_IO_,
60 $DISK_TYPE => $_SCST_DISK_IO_,
61 $DISKFILE_TYPE => $_SCST_DISK_FILE_IO_,
62 $CDROMFILE_TYPE => $_SCST_CDROM_FILE_IO_,
63 $DISKPERF_TYPE => $_SCST_DISKP_IO_,
64 $MODISK_TYPE => $_SCST_MODISK_IO_,
65 $MODISKPERF_TYPE => $_SCST_MODISKP_IO_,
66 $TAPE_TYPE => $_SCST_TAPE_IO_,
67 $TAPEPERF_TYPE => $_SCST_TAPEP_IO_);
69 my %_TYPE_MAP_ = ('dev_cdrom' => $CDROM_TYPE,
70 'dev_changer' => $CHANGER_TYPE,
71 'dev_disk' => $DISK_TYPE,
72 'disk_fileio' => $DISKFILE_TYPE,
73 'cdrom_fileio' => $CDROMFILE_TYPE,
74 'dev_disk_perf' => $DISKPERF_TYPE,
75 'dev_modisk' => $MODISK_TYPE,
76 'dev_modisk_perf' => $MODISKPERF_TYPE,
77 'dev_tape' => $TAPE_TYPE,
78 'dev_tape_perf' => $TAPEPERF_TYPE);
83 my $badVersion = $TRUE;
85 my $class = ref($this) || $this;
90 $self->{'debug'} = $debug if $debug;
92 my $scstVersion = $self->scstVersion();
94 my($major, $minor, $release) = split(/\./, $scstVersion, 3);
96 $badVersion = $FALSE if (($major > $_SCST_MIN_MAJOR_) ||
97 (($major == $_SCST_MIN_MAJOR_) && ($minor > $_SCST_MIN_MINOR_)) ||
98 (($major == $_SCST_MIN_MAJOR_) && ($minor == $_SCST_MIN_MINOR_) && ($release >= $_SCST_MIN_RELEASE_)));
100 croak("This module requires at least SCST version $_SCST_MIN_MAJOR_\.$_SCST_MIN_MINOR_\.".
101 "$_SCST_MIN_RELEASE_ and version $scstVersion was found") if ($badVersion);
109 my $io = new IO::File $_SCST_VERSION_IO_, O_RDONLY;
110 return $TRUE if (!$io);
121 my $dirHandle = new IO::Handle;
123 opendir $dirHandle, $_SCST_GROUPS_DIR_ or return undef;
125 foreach my $entry (readdir($dirHandle)) {
126 next if (($entry eq '.') || ($entry eq '..'));
128 push @groups, $entry;
139 my $groups = $self->groups();
141 foreach my $_group (@{$groups}) {
142 return $TRUE if ($group eq $_group);
152 return 2 if ($self->groupExists($group));
154 my $io = new IO::File $_SCST_IO_, O_WRONLY;
155 return $TRUE if (!$io);
157 my $cmd = "add_group $group\n";
159 if ($self->{'debug'}) {
160 print "DBG($$): $_SCST_IO_ -> $cmd\n";
167 return $FALSE if ($self->{'debug'});
168 return !$self->groupExists($group);
175 return 2 if (!$self->groupExists($group));
177 my $io = new IO::File $_SCST_IO_, O_WRONLY;
178 return $TRUE if (!$io);
180 my $cmd = "del_group $group\n";
182 if ($self->{'debug'}) {
183 print "DBG($$): $_SCST_IO_ -> $cmd\n";
190 return $FALSE if ($self->{'debug'});
191 return $self->groupExists($group);
196 my $io = new IO::File $_SCST_SGV_STATS_, O_RDONLY;
200 return undef if (!$io);
202 while (my $line = <$io>) {
205 if ($first || !$line) {
215 if ($line !~ /^\s/) {
216 ($stat, $hit, $total) = split(/\s+/, $line);
219 if ($stat eq 'big') {
224 (undef, $stat, $hit, $total) = split(/\s+/, $line);
226 if ($stat =~ /(\d+)K$/) {
228 $stat =~ s/\-$size\K//;
232 $stats{$stat}->{$size}->{'HITS'} = $hit;
233 $stats{$stat}->{$size}->{'TOTAL'} = $total;
243 my $io = new IO::File $_SCST_SESSIONS_, O_RDONLY;
247 return undef if (!$io);
249 while (my $line = <$io>) {
257 my($target, $user, $group, $commands) = split(/\s+/, $line);
259 $sessions{$target}->{$group}->{$user} = $commands;
269 my $io = new IO::File $_SCST_IO_, O_RDONLY;
273 return undef if (!$io);
275 while (my $line = <$io>) {
283 my($vname, $handler) = split(/\s+/, $line);
284 $devices{$vname} = $_TYPE_MAP_{$handler};
295 my $handler_io = $_IO_MAP_{$handler};
299 return undef if (!$handler_io);
300 return undef if (!$self->handlerExists($handler));
302 my $io = new IO::File $handler_io, O_RDONLY;
303 return undef if (!$io);
305 while (my $line = <$io>) {
313 my ($vname, $size, $blocksize, $options, $path) = split(/\s+/, $line);
315 if ($options =~ /^\//) {
320 $devices{$vname}->{'OPTIONS'} = $self->cleanupString($options);
321 $devices{$vname}->{'SIZE'} = $self->cleanupString($size);
322 $devices{$vname}->{'PATH'} = $self->cleanupString($path);
323 $devices{$vname}->{'BLOCKSIZE'} = $self->cleanupString($blocksize);
331 sub handlerDeviceExists {
335 my $devices = $self->handlerDevices($handler);
337 return -1 if (!defined($devices));
338 return $TRUE if (defined($$devices{$device}));
349 my $blocksize = shift;
350 my $handler_io = $_IO_MAP_{$handler};
352 return $TRUE if ($self->checkOptions($options));
353 return $TRUE if (!$handler_io);
354 return $TRUE if (!$self->handlerExists($handler));
355 return 2 if ($self->handlerDeviceExists($handler, $device));
357 $options = $self->cleanupString($options);
359 my $cmd = "open $device $path $blocksize $options\n";
361 $cmd = $self->cleanupString($cmd);
363 my $rc = $self->handler_private($handler_io, $cmd);
365 return $FALSE if ($self->{'debug'});
367 return !$self->handlerDeviceExists($handler, $device);
375 my $handler_io = $_IO_MAP_{$handler};
377 return $TRUE if (!$handler_io);
378 return $TRUE if (!$self->handlerExists($handler));
379 return 2 if (!$self->handlerDeviceExists($handler, $device));
381 my $cmd = "close $device $path\n";
383 my $rc = $self->handler_private($handler_io, $cmd);
385 return $FALSE if ($self->{'debug'});
387 return $self->handlerDeviceExists($handler, $device);
395 my $users = $self->users($group);
397 return -1 if (!defined($users));
399 foreach my $_user (@{$users}) {
400 return $TRUE if ($user eq $_user);
411 return undef if (!$self->groupExists($group));
413 my $io = new IO::File $_SCST_GROUPS_DIR_."/$group/".$_SCST_USERS_IO_, O_RDONLY;
414 return undef if (!$io);
416 while (my $line = <$io>) {
432 return $TRUE if (!$self->groupExists($group));
433 return 2 if ($self->userExists($user, $group));
435 my $cmd = "add $user\n";
437 my $rc = $self->group_private($group, $_SCST_USERS_IO_, $cmd);
439 return $FALSE if ($self->{'debug'});
441 return !$self->userExists($user, $group);
449 return $TRUE if (!$self->groupExists($group));
450 return 2 if (!$self->userExists($user, $group));
452 my $cmd = "del $user\n";
454 my $rc = $self->group_private($group, $_SCST_USERS_IO_, $cmd);
456 return $FALSE if ($self->{'debug'});
458 return $self->userExists($user, $group);
465 return $TRUE if (!$self->groupExists($group));
469 my $rc = $self->group_private($group, $_SCST_USERS_IO_, $cmd);
471 return $FALSE if ($self->{'debug'});
474 my $users = $self->users($group);
476 return ($#{$users} + 1);
482 my $handlers = $self->handlers();
484 foreach my $_handler (@{$handlers}) {
485 return $TRUE if ($handler eq $_handler);
495 my $dirHandle = new IO::Handle;
497 opendir $dirHandle, $_SCST_DIR_ or return undef;
499 foreach my $entry (readdir($dirHandle)) {
500 next if (($entry eq '.') || ($entry eq '..'));
502 if ((-d $_SCST_DIR_.'/'.$entry ) && (-f $_SCST_DIR_.'/'.$entry.'/type')) {
503 push @handlers, $_TYPE_MAP_{$entry} if ($_TYPE_MAP_{$entry});
512 sub groupDeviceExists {
517 my $devices = $self->groupDevices($group);
519 return -1 if (!defined($devices));
522 return $TRUE if ($$devices{$device} eq $lun);
524 return $TRUE if (defined($$devices{$device}));
536 return undef if (!$self->groupExists($group));
538 my $io = new IO::File $_SCST_GROUPS_DIR_."/$group/".$_SCST_DEVICES_IO_, O_RDONLY;
539 return undef if (!$io);
541 while (my $line = <$io>) {
549 my($vname, $lun) = split(/\s+/, $line);
551 $devices{$vname} = $lun;
559 sub assignDeviceToGroup {
565 return $TRUE if (!$self->groupExists($group));
566 return 2 if ($self->groupDeviceExists($device, $group, $lun));
568 my $cmd = "add $device $lun\n";
570 my $rc = $self->group_private($group, $_SCST_DEVICES_IO_, $cmd);
572 return $FALSE if ($self->{'debug'});
574 return !$self->groupDeviceExists($device, $group, $lun);
577 sub assignDeviceToHandler {
581 my $handler_io = $_IO_MAP_{$handler};
583 return $TRUE if (!$handler_io);
584 return $TRUE if (!$self->handlerExists($handler));
585 return 2 if ($self->handlerDeviceExists($handler, $device));
587 my $cmd = "assign $device $handler\n";
589 my $rc = $self->scst_private($cmd);
591 return $FALSE if ($self->{'debug'});
593 return !$self->handlerDeviceExists($handler, $device);
596 sub removeDeviceFromGroup {
601 return $TRUE if (!$self->groupExists($group));
602 return 2 if (!$self->groupDeviceExists($device, $group));
604 my $cmd = "del $device\n";
606 my $rc = $self->group_private($group, $_SCST_DEVICES_IO_, $cmd);
608 return $FALSE if ($self->{'debug'});
610 return $self->groupDeviceExists($device, $group);
613 sub clearGroupDevices {
617 return $TRUE if (!$self->groupExists($group));
621 my $rc = $self->group_private($group, $_SCST_DEVICES_IO_, $cmd);
623 return $FALSE if ($self->{'debug'});
626 my $devices = $self->groupDevices($group);
628 return (keys %{$devices});
631 sub handler_private {
633 my $handler_io = shift;
636 my $io = new IO::File $handler_io, O_WRONLY;
637 return $TRUE if (!$io);
639 if ($self->{'debug'}) {
640 print "DBG($$): '$handler_io' -> '$cmd'\n";
654 my $io = new IO::File $_SCST_IO_, O_WRONLY;
655 return $TRUE if (!$io);
657 if ($self->{'debug'}) {
658 print "DBG($$): '$_SCST_IO_' -> '$cmd'\n";
674 my $io = new IO::File $_SCST_GROUPS_DIR_."/$group/".$file, O_WRONLY;
675 return $TRUE if (!$io);
677 if ($self->{'debug'}) {
678 print "DBG($$): $_SCST_GROUPS_DIR_/$group/$file -> $cmd\n";
692 return if (!$options);
694 foreach my $option (split(/\s+/, $options)) {
695 foreach my $avail (@_AVAILABLE_OPTIONS_) {
696 return $FALSE if ($avail eq $option);
717 SCST::SCST - Generic SCST methods.
723 $p = SCST::SCST->new();
725 print "Using SCST version".$p->scstVersion()."\n";
727 if ($p->handlerDeviceExists($SCST::SCST::DISKFILE_TYPE)) {
728 print "openDevice() failed\n"
729 if ($p->openDevice($SCST::SCST::DISKFILE_TYPE, 'DISK01', '/vdisk/disk01.dsk'));
736 Generic SCST methods.
742 =item SCST::SCST->new();
744 Create a new SCST object. If the argument $debug is non-zero no changes
747 Arguments: (bool) $debug
749 Returns: (object) $new
751 =item SCST::SCST->scstVersion();
753 Returns the version of SCST running.
757 Returns: (string) $version
759 =item SCST::SCST->groups();
761 Returns a list of security groups configured.
765 Returns: (array ref) $groups
767 =item SCST::SCST->groupExists();
769 Checks for a specified group's existance.
771 Arguments: (string) $group
773 Returns: (boolean) $groupExists
775 =item SCST::SCST->addGroup();
777 Adds a security group to SCST's configuration. Returns 0 upon success, 1 if
778 unsuccessfull and 2 if the group already exists.
780 Arguments: (string) $group
782 Returns: (int) $success
784 =item SCST::SCST->removeGroup();
786 Removes a group from SCST's configuration. Returns 0 upon success, 1 if
787 unsuccessfull and 2 if group does not exist.
789 =item SCST::SCST->sgvStats();
791 Returns a hash of stats gathered from /proc/scsi_tgt/sgv.
795 Returns: (hash ref) $stats
797 Hash Layout: See /proc/scsi_tgt/sgv for tokens. This methods simply hashes
798 what's found there and returns it with no further processing.
800 =item SCST::SCST->sessions();
802 Returns a hash of current SCST initiator sessions.
806 Returns: (hash ref) $sessions
808 Hash Layout: See /proc/scsi_tgt/sessions for tokens. This methods simply hashes
809 what's found there and returns it with no further processing.
811 =item SCST::SCST->devices();
813 Returns a hash of devices configured without regard to device handler.
817 Returns: (hash ref) $devices
819 Hash Layout: (string) $device = (int) $handler
821 =item SCST::SCST->handlerDevices();
823 Returns a hash of devices configured for a specified device handler.
825 Arguments: (int) $handler
827 Returns: (hash ref) $devices
829 Hash Layout: (string) $device -> SIZE = (int) $deviceSize
830 (string) $device -> PATH = (string) $devicePath
831 (string) $device -> OPTIONS = (string) $options (comma seperated)
833 =item SCST::SCST->handlerDeviceExists();
835 Checks for a specified device is configured for a specified device handler.
837 Arguments: (int) $handler, (string) $device
839 Returns: (boolean) $deviceExists
841 =item SCST::SCST->openDevice();
843 Opens an already existing specified device for the specified device handler.
844 Returns 0 upon success, 1 if unsuccessfull and 2 if the device already exists.
846 Available options for the parameter $options are: WRITE_THROUGH, READ_ONLY, O_DIRECT
848 Arguments: (int) $handler, (string) $device, (string) $path [, (string) $options]
850 Returns: (int) $success
852 =item SCST::SCST->closeDevice();
854 Closes an open device configured for the specified device handler. Returns
855 0 upon success, 1 if unsuccessfull and 2 of the device does not exist.
857 Arguments: (int) $handler, (string) $device, (string) $path
859 Returns: (int) $success
861 =item SCST::SCST->userExists();
863 Checks for a specified user with the specified security group.
865 Arguments: (string) $user, (string) $group
867 Returns (boolean) $userExists
869 =item SCST::SCST->users();
871 Returns a list of users configured for a given security group.
873 Arguments: (string) $group
875 Returns: (hash ref) $users
877 =item SCST::SCST->addUser();
879 Adds the specified user to the specified security group. Returns 0
880 upon success, 1 if unsuccessfull and 2 if the user already exists.
882 Arguments: (string) $user, (string) $group
884 Returns: (int) $success
886 =item SCST::SCST->removeUser();
888 Removed the specified user from the specified security group. Returns
889 0 upon success, 1 if unsuccessfull and 2 if the user does not exist.
891 Arguments: (string) $user, (string) $group
893 Returns: (int) $success
895 =item SCST::SCST->clearUsers();
897 Removes all users from the specified security group. Returns 0 upon
898 success or 1 if unsuccessfull.
900 Arguments: (string) $group
902 Returns: (int) $success
904 =item SCST::SCST->handlerExists();
906 Checks if a specified device handler exists within SCST's configuration.
908 Arguments: (int) $handler
910 Returns: (boolean) $handlerExists
912 =item SCST::SCST->handlers();
914 Returns a list of configured device handlers.
918 Returns: (array ref) $handlers
920 =item SCST::SCST->groupDeviceExists();
922 Checks if a specified device is assigned to a specified security group.
923 If the optional $lun argument is specified, this method also matches
926 Arguments: (string) $device, (string) $group [, (int) $lun]
928 Returns: (boolean) $deviceExists
930 =item SCST::SCST->groupDevices();
932 Returns a hash if devices assigned to the specified security group.
934 Arguments: (string) $group
936 Returns: (hash ref) $devices
938 Hash Layout: (string) $device = (int) $lun
940 =item SCST::SCST->assignDeviceToGroup();
942 Assigns the specified device to the specified security group. Returns
943 0 upon success, 1 if unsuccessfull and 2 if the device has already
944 been assigned to the specified security group.
946 Arguments: (string) $device, (string) $group, (int) $lun
948 Returns: (int) $success
950 =item SCST::SCST->assignDeviceToHandler();
952 Assigns specified device to specified handler. Returns 0 upon success,
953 1 if unsuccessfull and 2 if the specified device is already assigned to
954 the specified handler.
956 Arguments: (string) $device, (string) $handler
958 Returns: (int) $success
960 =item SCST::SCST->removeDeviceFromGroup();
962 Removes the specified device from the specified security group. Returns
963 0 upon success, 1 if unsuccessfull and 2 if the device has not been
964 assigned to the specified security group.
966 Arguments: (string) $device, (string) $group
968 Returns: (int) $success
970 =item SCST::SCST->clearGroupDevices();
972 Removes all devices from the specified security group. Returns 0 upon
973 success or 1 if unsuccessfull.
975 Arguments: (string) $group
977 Returns: (int) $success
987 If the $debug parameter is specified on package new(), no actions are
988 performed. Rather they are printed to STDOUT and 0 is returned.
990 Available Device Handlers:
1003 To specify a device handler to a method, use the following syntax:
1005 $SCST::SCST::<handler type>
1009 $SCST::SCST::MODISK_TYPE