| # -*- mode: perl; perl-indent-level: 8; indent-tabs-mode: t -*- |
| |
| package SCST::SCST; |
| |
| # Author: Mark R. Buechler |
| # License: GPLv2 |
| # Copyright (c) 2005-2011 Mark R. Buechler |
| # Copyright (c) 2011-2019 Bart Van Assche <bvanassche@acm.org>. |
| |
| use strict; |
| use warnings; |
| use 5.005; |
| use Fcntl ':mode'; |
| use IO::Handle; |
| use IO::File; |
| use Carp qw(cluck); |
| |
| use POSIX; |
| |
| use constant { |
| TRUE => 1, |
| FALSE => 0, |
| |
| SCST_ROOT => '/sys/kernel/scst_tgt', |
| |
| # Root-level |
| SCST_SGV => 'sgv', |
| SCST_HANDLERS => 'handlers', |
| SCST_DEVICES => 'devices', |
| SCST_TARGETS => 'targets', |
| SCST_DEV_GROUPS => 'device_groups', |
| SCST_QUEUE_RES => 'last_sysfs_mgmt_res', |
| |
| # Device group specific |
| SCST_DG_DEVICES => 'devices', |
| SCST_DG_TGROUPS => 'target_groups', |
| |
| # Target specific |
| SCST_GROUPS => 'ini_groups', |
| SCST_INITIATORS => 'initiators', |
| SCST_SESSIONS => 'sessions', |
| SCST_LUNS => 'luns', |
| |
| # Files |
| SCST_MGMT_IO => 'mgmt', |
| SCST_VERSION_IO => 'version', |
| SCST_TRACE_IO => 'trace_level', |
| SCST_RESYNC_IO => 'resync_size', |
| SCST_T10_IO => 't10_dev_id', |
| |
| # Module return codes |
| SCST_C_FATAL_ERROR => 2, |
| SCST_C_BAD_ATTRIBUTES => 7, |
| SCST_C_ATTRIBUTE_STATIC => 8, |
| SCST_C_SETATTR_FAIL => 9, |
| |
| SCST_C_HND_NO_HANDLER => 10, |
| SCST_C_HND_BAD_ATTRIBUTES => 17, |
| SCST_C_HND_ATTRIBUTE_STATIC => 18, |
| SCST_C_HND_SETATTR_FAIL => 19, |
| |
| SCST_C_DEV_NO_DEVICE => 20, |
| SCST_C_DEV_EXISTS => 21, |
| SCST_C_DEV_OPEN_FAIL => 22, |
| SCST_C_DEV_CLOSE_FAIL => 23, |
| SCST_C_DEV_BAD_ATTRIBUTES => 27, |
| SCST_C_DEV_ATTRIBUTE_STATIC => 28, |
| SCST_C_DEV_SETATTR_FAIL => 29, |
| |
| SCST_C_DRV_NO_DRIVER => 30, |
| SCST_C_DRV_NOTVIRT => 31, |
| SCST_C_DRV_SETATTR_FAIL => 34, |
| SCST_C_DRV_ADDATTR_FAIL => 35, |
| SCST_C_DRV_REMATTR_FAIL => 36, |
| SCST_C_DRV_BAD_ATTRIBUTES => 37, |
| SCST_C_DRV_ATTRIBUTE_STATIC => 38, |
| SCST_C_DRV_SETATTR_FAIL => 39, |
| |
| SCST_C_TGT_NO_TARGET => 40, |
| SCST_C_TGT_EXISTS => 41, |
| SCST_C_TGT_ADD_FAIL => 42, |
| SCST_C_TGT_REM_FAIL => 43, |
| SCST_C_TGT_SETATTR_FAIL => 44, |
| SCST_C_TGT_ADDATTR_FAIL => 45, |
| SCST_C_TGT_REMATTR_FAIL => 46, |
| SCST_C_TGT_NO_LUN => 47, |
| SCST_C_TGT_ADD_LUN_FAIL => 48, |
| SCST_C_TGT_LUN_EXISTS => 49, |
| SCST_C_TGT_BAD_ATTRIBUTES => 50, |
| SCST_C_TGT_ATTRIBUTE_STATIC => 51, |
| SCST_C_TGT_SETATTR_FAIL => 52, |
| SCST_C_TGT_CLR_LUN_FAIL => 53, |
| SCST_C_TGT_BUSY => 54, |
| |
| SCST_C_GRP_NO_GROUP => 60, |
| SCST_C_GRP_EXISTS => 61, |
| SCST_C_GRP_ADD_FAIL => 62, |
| SCST_C_GRP_REM_FAIL => 63, |
| |
| SCST_C_GRP_NO_LUN => 70, |
| SCST_C_GRP_LUN_EXISTS => 71, |
| SCST_C_GRP_ADD_LUN_FAIL => 72, |
| SCST_C_GRP_REM_LUN_FAIL => 73, |
| SCST_C_GRP_CLR_LUN_FAIL => 75, |
| SCST_C_GRP_BAD_ATTRIBUTES => 77, |
| SCST_C_GRP_ATTRIBUTE_STATIC => 78, |
| SCST_C_GRP_SETATTR_FAIL => 79, |
| |
| SCST_C_GRP_NO_INI => 80, |
| SCST_C_GRP_INI_EXISTS => 81, |
| SCST_C_GRP_ADD_INI_FAIL => 82, |
| SCST_C_GRP_REM_INI_FAIL => 83, |
| SCST_C_GRP_MOV_INI_FAIL => 84, |
| SCST_C_GRP_CLR_INI_FAIL => 85, |
| |
| SCST_C_LUN_DEV_EXISTS => 91, |
| SCST_C_LUN_RPL_DEV_FAIL => 96, |
| SCST_C_LUN_BAD_ATTRIBUTES => 97, |
| SCST_C_LUN_ATTRIBUTE_STATIC => 98, |
| SCST_C_LUN_SETATTR_FAIL => 99, |
| |
| SCST_C_INI_BAD_ATTRIBUTES => 100, |
| SCST_C_INI_ATTRIBUTE_STATIC => 101, |
| SCST_C_INI_SETATTR_FAIL => 102, |
| |
| SCST_C_NO_SESSION => 110, |
| SCST_C_SESSION_CLOSE_FAIL => 111, |
| |
| SCST_C_DEV_GRP_NO_GROUP => 120, |
| SCST_C_DEV_GRP_EXISTS => 121, |
| SCST_C_DEV_GRP_ADD_FAIL => 122, |
| SCST_C_DEV_GRP_REM_FAIL => 123, |
| |
| SCST_C_ALUA_BAD_ATTRIBUTES => 125, |
| SCST_C_ALUA_ATTRIBUTE_STATIC => 126, |
| SCST_C_ALUA_SETATTR_FAIL => 127, |
| |
| SCST_C_DGRP_ADD_DEV_FAIL => 130, |
| SCST_C_DGRP_REM_DEV_FAIL => 131, |
| SCST_C_DGRP_NO_DEVICE => 132, |
| SCST_C_DGRP_DEVICE_EXISTS => 133, |
| SCST_C_DGRP_ADD_GRP_FAIL => 134, |
| SCST_C_DGRP_REM_GRP_FAIL => 135, |
| SCST_C_DGRP_NO_GROUP => 136, |
| SCST_C_DGRP_GROUP_EXISTS => 137, |
| SCST_C_DGRP_DEVICE_OTHER => 138, |
| |
| SCST_C_DGRP_BAD_ATTRIBUTES => 140, |
| SCST_C_DGRP_ATTRIBUTE_STATIC => 141, |
| SCST_C_DGRP_SETATTR_FAIL => 142, |
| |
| SCST_C_TGRP_BAD_ATTRIBUTES => 150, |
| SCST_C_TGRP_ATTRIBUTE_STATIC => 151, |
| SCST_C_TGRP_SETATTR_FAIL => 152, |
| |
| SCST_C_TGRP_ADD_TGT_FAIL => 160, |
| SCST_C_TGRP_REM_TGT_FAIL => 161, |
| SCST_C_TGRP_NO_TGT => 162, |
| SCST_C_TGRP_TGT_EXISTS => 163, |
| |
| SCST_C_TGRP_TGT_BAD_ATTR => 170, |
| SCST_C_TGRP_TGT_ATTR_STATIC => 171, |
| SCST_C_TGRP_TGT_SETATTR_FAIL => 172, |
| }; |
| |
| my %VERBOSE_ERROR = ( |
| (SCST_C_FATAL_ERROR) => 'A fatal error occurred. See "dmesg" for more information.', |
| (SCST_C_BAD_ATTRIBUTES) => 'Bad attributes given for SCST.', |
| (SCST_C_ATTRIBUTE_STATIC) => 'SCST attribute specified is static', |
| (SCST_C_SETATTR_FAIL) => 'Failed to set a SCST attribute. See "dmesg" for more information.', |
| |
| (SCST_C_HND_NO_HANDLER) => 'No such handler exists.', |
| (SCST_C_HND_BAD_ATTRIBUTES) => 'Bad attributes given for handler.', |
| (SCST_C_HND_ATTRIBUTE_STATIC) => 'Handler attribute given is static.', |
| (SCST_C_HND_SETATTR_FAIL) => 'Failed to set handler attribute. See "dmesg" for more information.', |
| |
| (SCST_C_DEV_NO_DEVICE) => 'No such device exists.', |
| (SCST_C_DEV_EXISTS) => 'Device already exists.', |
| (SCST_C_DEV_OPEN_FAIL) => 'Failed to open device. See "dmesg" for more information.', |
| (SCST_C_DEV_CLOSE_FAIL) => 'Failed to close device. See "dmesg" for more information.', |
| (SCST_C_DEV_BAD_ATTRIBUTES) => 'Bad attributes given for device.', |
| (SCST_C_DEV_ATTRIBUTE_STATIC) => 'Device attribute specified is static.', |
| (SCST_C_DEV_SETATTR_FAIL) => 'Failed to set device attribute. See "dmesg" for more information.', |
| |
| (SCST_C_DRV_NO_DRIVER) => 'No such driver exists.', |
| (SCST_C_DRV_NOTVIRT) => 'Driver is incapable of dynamically adding/removing targets or attributes.', |
| (SCST_C_DRV_ADDATTR_FAIL) => 'Failed to add driver dynamic attribute. See "dmesg" for more information.', |
| (SCST_C_DRV_REMATTR_FAIL) => 'Failed to remove driver dymanic attribute. See "dmesg" for more information.', |
| (SCST_C_DRV_BAD_ATTRIBUTES) => 'Bad attributes given for driver.', |
| (SCST_C_DRV_ATTRIBUTE_STATIC) => 'Driver attribute specified is static.', |
| (SCST_C_DRV_SETATTR_FAIL) => 'Failed to set driver attribute. See "dmesg" for more information.', |
| |
| (SCST_C_TGT_NO_TARGET) => 'No such target exists.', |
| (SCST_C_TGT_EXISTS) => 'Target already exists.', |
| (SCST_C_TGT_ADD_FAIL) => 'Failed to add target. See "dmesg" for more information.', |
| (SCST_C_TGT_REM_FAIL) => 'Failed to remove target. See "dmesg" for more information.', |
| (SCST_C_TGT_SETATTR_FAIL) => 'Failed to set target attribute. See "dmesg" for more information.', |
| (SCST_C_TGT_ADDATTR_FAIL) => 'Failed to add target dynamic attribute. See "dmesg" for more information.', |
| (SCST_C_TGT_REMATTR_FAIL) => 'Failed to remove target dynamic attribute. See "dmesg" for more information.', |
| (SCST_C_TGT_NO_LUN) => 'No such LUN exists.', |
| (SCST_C_TGT_ADD_LUN_FAIL) => 'Failed to add LUN to target. See "dmesg" for more information.', |
| (SCST_C_TGT_LUN_EXISTS) => 'LUN already exists.', |
| (SCST_C_TGT_BAD_ATTRIBUTES) => 'Bad attributes given for target.', |
| (SCST_C_TGT_ATTRIBUTE_STATIC) => 'Target attribute specified is static.', |
| (SCST_C_TGT_SETATTR_FAIL) => 'Failed to set target attribute. See "dmesg" for more information.', |
| (SCST_C_TGT_CLR_LUN_FAIL) => 'Failed to clear LUNs from target. See "dmesg" for more information.', |
| (SCST_C_TGT_BUSY) => 'Failed to remove target - target has active sessions. See "dmesg" for more information.', |
| |
| (SCST_C_GRP_NO_GROUP) => 'No such group exists.', |
| (SCST_C_GRP_EXISTS) => 'Group already exists.', |
| (SCST_C_GRP_ADD_FAIL) => 'Failed to add group. See "dmesg" for more information.', |
| (SCST_C_GRP_REM_FAIL) => 'Failed to remove group. See "dmesg" for more information.', |
| |
| (SCST_C_GRP_NO_LUN) => 'No such LUN exists.', |
| (SCST_C_GRP_LUN_EXISTS) => 'LUN already exists.', |
| (SCST_C_GRP_ADD_LUN_FAIL) => 'Failed to add LUN to group. See "dmesg" for more information.', |
| (SCST_C_GRP_REM_LUN_FAIL) => 'Failed to remove LUN. See "dmesg" for more information.', |
| (SCST_C_GRP_CLR_LUN_FAIL) => 'Failed to clear LUNs from group. See "dmesg" for more information.', |
| (SCST_C_GRP_BAD_ATTRIBUTES) => 'Bad attributes given for group.', |
| (SCST_C_GRP_ATTRIBUTE_STATIC) => 'Group attribute specified is static.', |
| (SCST_C_GRP_SETATTR_FAIL) => 'Failed to set group attribute. See "dmesg" for more information.', |
| |
| (SCST_C_GRP_NO_INI) => 'No such initiator exists.', |
| (SCST_C_GRP_INI_EXISTS) => 'Initiator already exists.', |
| (SCST_C_GRP_ADD_INI_FAIL) => 'Failed to add initiator. See "dmesg" for more information.', |
| (SCST_C_GRP_REM_INI_FAIL) => 'Failed to remove initiator. See "dmesg" for more information.', |
| (SCST_C_GRP_MOV_INI_FAIL) => 'Failed to move initiator. See "dmesg" for more information.', |
| (SCST_C_GRP_CLR_INI_FAIL) => 'Failed to clear initiators. See "dmesg" for more information.', |
| |
| (SCST_C_LUN_DEV_EXISTS) => 'Device already exists for LUN.', |
| (SCST_C_LUN_RPL_DEV_FAIL) => 'Failed to replace device for LUN. See "dmesg" for more information.', |
| (SCST_C_LUN_BAD_ATTRIBUTES) => 'Bad attributes for LUN.', |
| (SCST_C_LUN_ATTRIBUTE_STATIC) => 'LUN attribute specified is static.', |
| (SCST_C_LUN_SETATTR_FAIL) => 'Failed to set LUN attribute. See "dmesg" for more information.', |
| |
| (SCST_C_INI_BAD_ATTRIBUTES) => 'Bad attributes for initiator.', |
| (SCST_C_INI_ATTRIBUTE_STATIC) => 'Initiator attribute specified is static.', |
| (SCST_C_INI_SETATTR_FAIL) => 'Failed to set initiator attribute. See "dmesg" for more information.', |
| |
| (SCST_C_NO_SESSION) => 'Session not found for driver/target.', |
| (SCST_C_SESSION_CLOSE_FAIL) => 'Failed to close session.', |
| |
| (SCST_C_DEV_GRP_NO_GROUP) => 'No such device group exists.', |
| (SCST_C_DEV_GRP_EXISTS) => 'Device group already exists.', |
| (SCST_C_DEV_GRP_ADD_FAIL) => 'Failed to add device group. See "dmesg" for more information.', |
| (SCST_C_DEV_GRP_REM_FAIL) => 'Failed to remove device group. See "dmesg" for more information.', |
| |
| (SCST_C_DGRP_ADD_DEV_FAIL) => 'Failed to add device to device group. See "dmesg" for more information.', |
| (SCST_C_DGRP_REM_DEV_FAIL) => 'Failed to remove device from device group. See "dmesg" for more information.', |
| (SCST_C_DGRP_NO_DEVICE) => 'No such device in device group.', |
| (SCST_C_DGRP_DEVICE_EXISTS) => 'Device already exists within device group.', |
| (SCST_C_DGRP_ADD_GRP_FAIL) => 'Failed to add target group to device group. See "dmesg" for more information.', |
| (SCST_C_DGRP_REM_GRP_FAIL) => 'Failed to remove target group from device group. See "dmesg" for more information.', |
| (SCST_C_DGRP_NO_GROUP) => 'No such target group exists within device group.', |
| (SCST_C_DGRP_GROUP_EXISTS) => 'Target group already exists within device group.', |
| (SCST_C_DGRP_DEVICE_OTHER) => 'Device is already assigned to another device group.', |
| |
| (SCST_C_DGRP_BAD_ATTRIBUTES) => 'Bad attributes for device group.', |
| (SCST_C_DGRP_ATTRIBUTE_STATIC) => 'Device group attribute specified is static.', |
| (SCST_C_DGRP_SETATTR_FAIL) => 'Failed to set device group attribute. See "dmesg" for more information.', |
| |
| (SCST_C_TGRP_BAD_ATTRIBUTES) => 'Bad attributes for target group.', |
| (SCST_C_TGRP_ATTRIBUTE_STATIC) => 'Target group attribute specified is static.', |
| (SCST_C_TGRP_SETATTR_FAIL) => 'Failed to set target group attribute. See "dmesg" for more information.', |
| |
| (SCST_C_TGRP_ADD_TGT_FAIL) => 'Failed to add target to target group.', |
| (SCST_C_TGRP_REM_TGT_FAIL) => 'Failed to remove target from target group.', |
| (SCST_C_TGRP_NO_TGT) => 'No such target exists within target group.', |
| (SCST_C_TGRP_TGT_EXISTS) => 'Target already exists within target group.', |
| |
| (SCST_C_TGRP_TGT_BAD_ATTR) => 'Bad attributes for target group target.', |
| (SCST_C_TGRP_TGT_ATTR_STATIC) => 'Target group target attribute specified is static.', |
| (SCST_C_TGRP_TGT_SETATTR_FAIL) => 'Failed to set target group target attribute. See "dmesg" for more information.', |
| ); |
| |
| use vars qw(@ISA @EXPORT $VERSION); |
| |
| use vars qw($TGT_TYPE_HARDWARE $TGT_TYPE_VIRTUAL); |
| |
| $VERSION = '1.0.0'; |
| |
| $TGT_TYPE_HARDWARE = 1; |
| $TGT_TYPE_VIRTUAL = 2; |
| |
| my $TIMEOUT = 300; # Command execution timeout |
| |
| my $_SCST_MIN_MAJOR_ = 2; |
| my $_SCST_MIN_MINOR_ = 0; |
| my $_SCST_MIN_RELEASE_ = 0; |
| |
| sub SCST_ROOT_DIR { |
| return SCST_ROOT; |
| } |
| |
| sub SCST_SGV_DIR { |
| return SCST_ROOT . '/sgv'; |
| } |
| |
| sub SCST_QUEUE_RES_PATH { |
| return SCST_ROOT . '/' . SCST_QUEUE_RES; |
| } |
| |
| # Device handlers. |
| sub SCST_HANDLERS_DIR { |
| return SCST_ROOT . '/' . SCST_HANDLERS; |
| } |
| |
| # Device instances. |
| sub SCST_DEVICES_DIR { |
| return SCST_ROOT . '/' . SCST_DEVICES; |
| } |
| |
| # Target drivers. |
| sub SCST_TARGETS_DIR { |
| return SCST_ROOT . '/' . SCST_TARGETS; |
| } |
| |
| # ALUA Device groups. |
| sub SCST_DEV_GROUP_DIR { |
| return SCST_ROOT . '/' . SCST_DEV_GROUPS; |
| } |
| |
| sub new { |
| my $this = shift; |
| my $debug = shift; |
| my $badVersion = 1; |
| |
| my $class = ref($this) || $this; |
| my $self = {}; |
| |
| bless($self, $class); |
| |
| $self->{'debug'} = $debug; |
| |
| my $scstVersion = $self->scstVersion(); |
| |
| die("Failed to obtain SCST version information. Are the SCST modules loaded?\n") |
| if (!defined($scstVersion)); |
| |
| ($scstVersion, undef) = split(/\-/, $scstVersion); |
| my($major, $minor, $release) = split(/\./, $scstVersion, 3); |
| |
| ($release, undef) = split(/\-/, $release) if ($release =~ /\-/); |
| |
| $badVersion = 0 if (($major > $_SCST_MIN_MAJOR_) || |
| (($major == $_SCST_MIN_MAJOR_) && ($minor > $_SCST_MIN_MINOR_)) || |
| (($major == $_SCST_MIN_MAJOR_) && ($minor == $_SCST_MIN_MINOR_) && |
| ($release >= $_SCST_MIN_RELEASE_))); |
| |
| die("This module requires at least SCST version $_SCST_MIN_MAJOR_\.$_SCST_MIN_MINOR_\.". |
| "$_SCST_MIN_RELEASE_ and version $scstVersion was found") if ($badVersion); |
| |
| return $self; |
| } |
| |
| # Returns 1 if and only if the owner of a file is not allowed to write to a |
| # file. |
| sub readOnly { |
| my ($path) = @_; |
| my $mode = (stat($path))[2]; |
| |
| if (!defined($mode)) { |
| cluck("invalid path $path"); |
| return undef; |
| } |
| return ($mode & S_IWUSR) == 0; |
| } |
| |
| sub scstVersion { |
| my $self = shift; |
| |
| my ($attributes, $errorString) = $self->scstAttributes(); |
| |
| return undef if (!defined($attributes)); |
| return $$attributes{'version'}->{'value'}; |
| } |
| |
| sub scstAttributes { |
| my $self = shift; |
| my %attributes = ( ); |
| |
| my $pHandle = new IO::Handle; |
| my $_path = SCST_ROOT_DIR(); |
| if (!(opendir $pHandle, $_path)) { |
| return (undef, "scstAttributes(): Unable to read directory '$_path': $!"); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO); |
| my $pPath = make_path(SCST_ROOT_DIR(), $attribute); |
| my $mode = (stat($pPath))[2]; |
| |
| if (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if (($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "scsiAttributes(): Unable to read ". |
| "scst attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| if ($attribute eq SCST_TRACE_IO) { |
| $attributes{$attribute}->{'value'} = $value; |
| my @possible; |
| $value = ''; |
| my $start = FALSE; |
| while (my $line = <$io>) { |
| $start = TRUE if ($line !~ /\[/); |
| $value .= $line if ($start); |
| } |
| $value =~ s/\n//g; |
| |
| if ($value =~ /\[(.*)\]/) { |
| $value = $1; |
| |
| foreach my $t (split(/\,/, $value)) { |
| $t =~ s/^\s+//; $t =~ s/\s+$//; |
| push @possible, $t; |
| } |
| } |
| $attributes{$attribute}->{'set'} = \@possible; |
| } else { |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| close $io; |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| # Older Perl versions complain if the argument of length() is undefined. Hence |
| # this function that checks whether its arguments are defined and not empty. |
| sub valid { |
| for my $arg (@_) { |
| return FALSE if (!defined($arg) || $arg eq ""); |
| } |
| return TRUE; |
| } |
| |
| # Convert e.g. EINVAL into "EINVAL". |
| sub my_strerror { |
| my ($errorcode) = @_; |
| |
| return $errorcode if (!defined($errorcode)); |
| for my $errstr (keys(%!)) { |
| my $err = eval($errstr); |
| return $errstr if (defined($err) and $err == $errorcode); |
| } |
| return $errorcode; |
| } |
| |
| sub setAttrFailed { |
| my ($path, $bytes, $no_such_attr, $is_static, $failed) = @_; |
| |
| print STDERR "(" . my_strerror(-$bytes) . ") "; |
| return $no_such_attr if !(-f $path); |
| return $is_static if readOnly($path); |
| return $failed; |
| } |
| |
| sub setScstAttribute { |
| my $self = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if (!valid($attribute) || !defined($value)); |
| |
| # There is a space between the unary minus sign and ENOENT because |
| # without that space older Perl versions report the following warning: |
| # Ambiguous use of -ENOENT resolved as -&ENOENT() at |
| # /usr/share/perl5/vendor_perl/SCST/SCST.pm line 497. |
| my $bytes = - ENOENT; |
| my $path = make_path(SCST_ROOT_DIR(), $attribute); |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $attribute = $value\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| return setAttrFailed($path, $bytes, SCST_C_BAD_ATTRIBUTES, |
| SCST_C_ATTRIBUTE_STATIC, SCST_C_SETATTR_FAIL); |
| } |
| |
| sub drivers { |
| my $self = shift; |
| my $dHandle = new IO::Handle; |
| my $_path = SCST_TARGETS_DIR(); |
| my @drivers; |
| |
| if (opendir($dHandle, $_path)) { |
| foreach my $driver (readdir($dHandle)) { |
| next if ($driver eq '.' || $driver eq '..'); |
| |
| if (-d make_path(SCST_TARGETS_DIR(), $driver)) { |
| push @drivers, $driver; |
| } |
| } |
| @drivers = sort(@drivers); |
| close $dHandle; |
| } else { |
| return (undef, "drivers(): Unable to read directory '$_path': $!"); |
| } |
| |
| return (\@drivers, undef); |
| } |
| |
| |
| sub targets { |
| my $self = shift; |
| my $driver = shift; |
| |
| return (undef, "Too few arguments") if (!valid($driver)); |
| |
| my $tHandle = new IO::Handle; |
| my $_path = make_path(SCST_TARGETS_DIR(), $driver); |
| if (opendir $tHandle, $_path) { |
| my @targets; |
| |
| foreach my $target (readdir($tHandle)) { |
| next if ($target eq '.' || $target eq '..' || |
| $target eq 'module'); |
| |
| if (-d make_path(SCST_TARGETS_DIR(), $driver, |
| $target)) { |
| push @targets, $target; |
| } |
| } |
| close $tHandle; |
| @targets = sort(@targets); |
| return (\@targets, undef); |
| } |
| my $errorString; |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "targets(): Driver '$driver' is not available"; |
| } else { |
| $errorString = "targets(): Unable to read directory '$_path': $!"; |
| } |
| |
| return (undef, $errorString); |
| } |
| |
| sub groups { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| |
| return (undef, "Too few arguments") if (!valid($driver, $target)); |
| |
| my $gHandle = new IO::Handle; |
| my $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS); |
| |
| if (opendir $gHandle, $_path) { |
| my @groups; |
| |
| foreach my $group (readdir($gHandle)) { |
| next if ($group eq '.' || $group eq '..'); |
| |
| if (-d make_path(SCST_TARGETS_DIR(), $driver, |
| $target, SCST_GROUPS, $group)) { |
| push @groups, $group; |
| } |
| } |
| close $gHandle; |
| @groups = sort(@groups); |
| return (\@groups, undef); |
| } |
| |
| my $errorString; |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "groups(): Driver '$driver' is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "groups(): Target '$target' is not available"; |
| } else { |
| $errorString = "groups(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| sub initiators { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my @initiators; |
| my $errorString; |
| |
| return (undef, "Too few arguments") |
| if (!valid($driver, $target, $group)); |
| |
| my $iHandle = new IO::Handle; |
| my $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| $group, SCST_INITIATORS); |
| if (!(opendir $iHandle, $_path)) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "initiators(): Driver '$driver' is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "initiators(): Target '$target' is not available"; |
| } elsif ($self->groupExists($driver, $target, $group) != TRUE) { |
| $errorString = "initiators(): Group '$group' does not exist"; |
| } else { |
| $errorString = "initiators(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $initiator (readdir($iHandle)) { |
| next if (($initiator eq '.') || ($initiator eq '..')); |
| next if ($initiator eq SCST_MGMT_IO); |
| |
| push @initiators, $initiator; |
| } |
| |
| close $iHandle; |
| |
| return (\@initiators, undef); |
| } |
| |
| sub luns { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $errorString; |
| |
| return (undef, "Too few arguments") if (!valid($driver, $target)); |
| |
| my $_path; |
| |
| if (valid($group)) { |
| $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, SCST_LUNS); |
| } else { |
| $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_LUNS); |
| } |
| |
| my $lHandle = new IO::Handle; |
| |
| if (!(opendir $lHandle, $_path)) { |
| if (valid($group) && |
| $self->groupExists($driver, $target, $group) != TRUE) { |
| $errorString = "initiators(): Group '$group' does not exist"; |
| } elsif ($self->driverExists($driver) != TRUE) { |
| $errorString = "luns(): Driver '$driver' is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "luns(): Target '$target' is not available"; |
| } else { |
| $errorString = "luns(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| my %luns; |
| |
| foreach my $lun (readdir($lHandle)) { |
| next if (($lun eq '.') || ($lun eq '..')); |
| |
| my $lPath = make_path($_path, $lun); |
| |
| if (-d $lPath) { |
| my $_lHandle = new IO::Handle; |
| |
| if (!(opendir $_lHandle, $lPath)) { |
| return (undef, "luns(): Unable to read directory '$lPath': $!"); |
| } |
| |
| foreach my $attribute (readdir($_lHandle)) { |
| my $pPath = make_path($lPath, $attribute); |
| |
| if (-l $pPath) { |
| my $linked = readlink($pPath); |
| $linked =~ s/.*\///; |
| $luns{$lun} = $linked; |
| } |
| } |
| |
| close $_lHandle; |
| } |
| } |
| |
| close $lHandle; |
| |
| return \%luns; |
| } |
| |
| sub aluaAttributes { |
| my $self = shift; |
| my %attributes = ( ); |
| |
| my $pHandle = new IO::Handle; |
| my $_path = SCST_DEV_GROUP_DIR(); |
| if (!(opendir $pHandle, $_path)) { |
| return (undef, "deviceGroupsAttributes(): Unable to read directory '$_path': $!"); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO || $attribute eq 'uevent'); |
| my $pPath = make_path(SCST_DEV_GROUP_DIR(), $attribute); |
| my $mode = (stat($pPath))[2]; |
| |
| if (!($mode & S_IRUSR)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static = !($mode & S_IWUSR); |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "aluaAttributes(): Unable to read device attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $second_line = <$io>; |
| $second_line = "" if (!defined($second_line)); |
| if ($second_line =~ /\[key\]/) { |
| my $key = 0; |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| close $io; |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub deviceGroups { |
| my $self = shift; |
| my @groups; |
| |
| my $dHandle = new IO::Handle; |
| my $_path = SCST_DEV_GROUP_DIR(); |
| if (!(opendir $dHandle, $_path)) { |
| return (undef, "deviceGroups(): Unable to read directory '$_path': $!"); |
| } |
| |
| foreach my $group (readdir($dHandle)) { |
| next if (($group eq '.') || ($group eq '..')); |
| |
| if (-d make_path(SCST_DEV_GROUP_DIR(), $group)) { |
| push @groups, $group; |
| } |
| } |
| |
| close $dHandle; |
| @groups = sort(@groups); |
| return (\@groups, undef); |
| } |
| |
| sub deviceGroupDevices { |
| my $self = shift; |
| my $group = shift; |
| my @devices; |
| my $errorString; |
| |
| return (undef, "Too few arguments") if (!valid($group)); |
| |
| my $dHandle = new IO::Handle; |
| my $_path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_DEVICES); |
| if (!(opendir $dHandle, $_path)) { |
| if ($self->deviceGroupExists($group) != TRUE) { |
| $errorString = "deviceGroupDevices(): Device group '$group' does not exist"; |
| } else { |
| $errorString = "deviceGroupDevices(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $device (readdir($dHandle)) { |
| next if (($device eq '.') || ($device eq '..')); |
| |
| if (-d make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_DEVICES, $device)) { |
| push @devices, $device; |
| } |
| } |
| |
| close $dHandle; |
| |
| return (\@devices, undef); |
| } |
| |
| sub targetGroups { |
| my $self = shift; |
| my $group = shift; |
| my @tgroups; |
| my $errorString; |
| |
| return (undef, "Too few arguments") if (!valid($group)); |
| |
| my $dHandle = new IO::Handle; |
| my $_path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS); |
| if (!(opendir $dHandle, $_path)) { |
| if ($self->deviceGroupExists($group) != TRUE) { |
| $errorString = "targetGroups(): Device group '$group' does not exist"; |
| } else { |
| $errorString = "targetGroups(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $tgroup (readdir($dHandle)) { |
| next if (($tgroup eq '.') || ($tgroup eq '..')); |
| |
| if (-d make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, $tgroup)) { |
| push @tgroups, $tgroup; |
| } |
| } |
| |
| close $dHandle; |
| |
| return (\@tgroups, undef); |
| } |
| |
| sub targetGroupTargets { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| my @targets; |
| my $errorString; |
| |
| return (undef, "Too few arguments") if (!valid($group, $tgroup)); |
| |
| my $dHandle = new IO::Handle; |
| my $_path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, $tgroup); |
| if (!(opendir $dHandle, $_path)) { |
| if ($self->deviceGroupExists($group) != TRUE) { |
| $errorString = "targetGroupTargets(): Device group '$group' does not exist"; |
| } elsif ($self->targetGroupExists($group, $tgroup) != TRUE) { |
| $errorString = "targetGroupTargets(): Target group '$tgroup' does not exist"; |
| } else { |
| $errorString = "targetGroupTargets(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $tgt (readdir($dHandle)) { |
| next if (($tgt eq '.') || ($tgt eq '..')); |
| |
| if (-d make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, $tgroup, $tgt)) { |
| push @targets, $tgt; |
| } |
| } |
| |
| close $dHandle; |
| |
| @targets = sort(@targets); |
| |
| return (\@targets, undef); |
| } |
| |
| sub driverExists { |
| my $self = shift; |
| my $driver = shift; |
| my $dHandle = new IO::Handle; |
| my $result; |
| |
| $result = valid($driver) && |
| opendir($dHandle, make_path(SCST_TARGETS_DIR(), $driver)); |
| close $dHandle if ($result); |
| |
| return $result ? TRUE : FALSE; |
| } |
| |
| sub driverDynamicAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my %attributes = ( ); |
| my $available; |
| my $errorString; |
| |
| return (undef, "Too few arguments") if (!valid($driver)); |
| |
| my $io = new IO::File make_path(SCST_TARGETS_DIR(), $driver, |
| SCST_MGMT_IO), O_RDONLY; |
| |
| if (!$io) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "driverDynamicAttributes(): Driver '$driver' ". |
| "is not available"; |
| } else { |
| $errorString = "driverDynamicAttributes(): Unable to open mgmt ". |
| "interface for driver '$driver': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| while (my $in = <$io>) { |
| if ($in =~ /^The following target driver attributes available\:/) { |
| (undef, $available) = split(/\:/, $in, 2); |
| $available =~ s/\.$//; |
| } |
| } |
| close $io; |
| |
| if ($available) { |
| foreach my $attribute (split(/\,/, $available)) { |
| $attribute =~ s/^\s+//; |
| $attribute =~ s/\s+$//; |
| $attributes{$attribute} = ''; |
| } |
| } |
| |
| return (\%attributes, undef); |
| } |
| |
| sub checkDriverDynamicAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $check = shift; |
| |
| return TRUE if (!valid($driver)); |
| |
| my ($available, $errorString) = $self->driverDynamicAttributes($driver); |
| |
| if (!defined($available)) { |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if (!$rc > 1); |
| |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| return FALSE if (!defined($check)); |
| |
| if (ref($check) eq 'HASH') { |
| foreach my $attribute (keys %{$check}) { |
| if (!defined($$available{$attribute})) { |
| return TRUE; |
| } |
| } |
| } else { |
| if (!defined($$available{$check})) { |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| sub addDriverDynamicAttribute { |
| my $self = shift; |
| my $driver = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return SCST_C_DRV_ADDATTR_FAIL if (!valid($driver, $attribute) || |
| !defined($value)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, SCST_MGMT_IO); |
| $cmd .= "add_attribute $attribute $value"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DRV_NOTVIRT if (!$self->driverIsVirtualCapable($driver)); |
| |
| $rc = $self->checkDriverDynamicAttributes($driver, $attribute); |
| return SCST_C_DRV_BAD_ATTRIBUTES if ($rc == 1); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DRV_ADDATTR_FAIL; |
| } |
| |
| sub removeDriverDynamicAttribute { |
| my $self = shift; |
| my $driver = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return SCST_C_DRV_REMATTR_FAIL if (!valid($driver, $attribute) || |
| !defined($value)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, SCST_MGMT_IO); |
| $cmd .= "del_attribute $attribute $value"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DRV_NOTVIRT if (!$self->driverIsVirtualCapable($driver)); |
| |
| $rc = $self->checkDriverDynamicAttributes($driver, $attribute); |
| return SCST_C_DRV_BAD_ATTRIBUTES if ($rc == 1); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DRV_REMATTR_FAIL; |
| } |
| |
| sub targetExists { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| |
| return valid($driver, $target) && |
| $target ne '.' && $target ne '..' && $target ne 'module' && |
| (-d make_path(SCST_TARGETS_DIR(), $driver, $target)) ? TRUE : FALSE; |
| } |
| |
| sub driverIsVirtualCapable { |
| my $self = shift; |
| my $driver = shift; |
| my $path = make_path(SCST_TARGETS_DIR(), $driver, SCST_MGMT_IO); |
| return (-w $path) ? TRUE : FALSE; |
| } |
| |
| sub targetType { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $errorString; |
| |
| return (undef, "Too few arguments") if (!valid($driver, $target)); |
| |
| if ($self->driverIsVirtualCapable($driver)) { |
| my $attribs; |
| ($attribs, $errorString) = $self->targetAttributes($driver, $target); |
| |
| if (defined($$attribs{'hw_target'}) && |
| ($$attribs{'hw_target'}->{'value'} == TRUE)) { |
| return $TGT_TYPE_HARDWARE; |
| } else { |
| return $TGT_TYPE_VIRTUAL; |
| } |
| } |
| |
| return $TGT_TYPE_HARDWARE; |
| } |
| |
| sub addVirtualTarget { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $attributes = shift; |
| |
| my $o_string = ""; |
| foreach my $attribute (keys %{$attributes}) { |
| if (ref($$attributes{$attribute}) eq 'ARRAY') { |
| foreach my $value (@{$$attributes{$attribute}}) { |
| $o_string .= "$attribute=$value;"; |
| } |
| } else { |
| my $value = $$attributes{$attribute}; |
| $o_string .= "$attribute=$value;"; |
| } |
| } |
| |
| $o_string =~ s/\s$//; |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, SCST_MGMT_IO); |
| $cmd .= "add_target $target $o_string"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_EXISTS if ($rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DRV_NOTVIRT if (!$self->driverIsVirtualCapable($driver)); |
| |
| $rc = $self->checkTargetCreateAttributes($driver, $attributes); |
| return SCST_C_TGT_BAD_ATTRIBUTES if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_TGT_ADD_FAIL; |
| } |
| |
| sub targetDynamicAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my %attributes = ( ); |
| my $available; |
| my $errorString; |
| |
| return (undef, "Too few arguments") if (!valid($driver)); |
| |
| my $io = new IO::File make_path(SCST_TARGETS_DIR(), $driver, |
| SCST_MGMT_IO), O_RDONLY; |
| |
| if (!$io) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "targetDynamicAttributes(): Driver '$driver' ". |
| "is not available"; |
| } else { |
| $errorString = "targetDynamicAttributes(): Unable to open mgmt ". |
| "interface for driver '$driver': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| while (my $in = <$io>) { |
| if ($in =~ /^The following target attributes available\:/) { |
| (undef, $available) = split(/\:/, $in, 2); |
| $available =~ s/\.$//; |
| } |
| } |
| close $io; |
| |
| if ($available) { |
| foreach my $attribute (split(/\,/, $available)) { |
| $attribute =~ s/^\s+//; |
| $attribute =~ s/\s+$//; |
| $attributes{$attribute} = ''; |
| } |
| } |
| |
| return (\%attributes, undef); |
| } |
| |
| sub checkTargetDynamicAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $check = shift; |
| |
| my ($available, $errorString) = $self->targetDynamicAttributes($driver); |
| |
| if (!defined($available)) { |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if (!$rc > 1); |
| |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| return FALSE if (!defined($check)); |
| |
| if (ref($check) eq 'HASH') { |
| foreach my $attribute (keys %{$check}) { |
| if (!defined($$available{$attribute})) { |
| return TRUE; |
| } |
| } |
| } else { |
| if (!defined($$available{$check})) { |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| sub addTargetDynamicAttribute { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return SCST_C_TGT_ADDATTR_FAIL |
| if (!valid($driver, $target, $attribute) || !defined($value)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, SCST_MGMT_IO); |
| $cmd .= "add_target_attribute $target $attribute $value"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DRV_NOTVIRT if (!$self->driverIsVirtualCapable($driver)); |
| |
| $rc = $self->checkTargetDynamicAttributes($driver, $attribute); |
| return SCST_C_TGT_BAD_ATTRIBUTES if ($rc == 1); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_TGT_ADDATTR_FAIL; |
| } |
| |
| sub removeTargetDynamicAttribute { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return SCST_C_TGT_REMATTR_FAIL |
| if (!valid($driver, $target, $attribute) || !defined($value)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, SCST_MGMT_IO); |
| $cmd .= "del_target_attribute $target $attribute $value"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DRV_NOTVIRT if (!$self->driverIsVirtualCapable($driver)); |
| |
| $rc = $self->checkTargetDynamicAttributes($driver, $attribute); |
| return SCST_C_TGT_BAD_ATTRIBUTES if ($rc == 1); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_TGT_REMATTR_FAIL; |
| } |
| |
| sub removeVirtualTarget { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| |
| # May fail if the target does not have an 'enabled' attribute as is the |
| # case for e.g. the 'scst_local' driver. |
| $self->enableTarget($driver, $target, FALSE); |
| |
| my ($sessions, $errorString) = $self->sessions($driver, $target); |
| |
| my %can_close; |
| foreach my $session (keys %{$sessions}) { |
| if (defined($$sessions{$session}->{'force_close'})) { |
| $can_close{$session}++; |
| my $rc = $self->closeSession($driver, $target, $session); |
| return $rc if ($rc); |
| } |
| } |
| |
| if (scalar keys %can_close) { |
| my $has_sessions = 1; |
| my $now = time(); |
| while ($has_sessions && (($now + $TIMEOUT) > time())) { |
| ($sessions, $errorString) = $self->sessions($driver, $target); |
| |
| foreach my $session (keys %can_close) { |
| if (!defined($$sessions{$session})) { |
| delete $can_close{$session}; |
| } |
| } |
| |
| $has_sessions = scalar keys %can_close; |
| sleep 1 if ($has_sessions); |
| } |
| |
| return SCST_C_TGT_BUSY if ($has_sessions); |
| } |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, SCST_MGMT_IO); |
| $cmd .= "del_target $target"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DRV_NOTVIRT if (!$self->driverIsVirtualCapable($driver)); |
| |
| return SCST_C_TGT_REM_FAIL; |
| } |
| |
| sub groupExists { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| |
| return FALSE if (!valid($driver, $target, $group)); |
| |
| my ($groups, $errorString) = $self->groups($driver, $target); |
| |
| if (!defined($groups)) { |
| my $rc = $self->targetExists($driver, $target); |
| return FALSE if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| foreach my $_group (@{$groups}) { |
| return TRUE if ($group eq $_group); |
| } |
| |
| return FALSE; |
| } |
| |
| sub initiatorExists { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $initiator = shift; |
| |
| return FALSE if (!valid($driver, $target, $group, $initiator)); |
| |
| my ($initiators, $errorString) = $self->initiators($driver, $target, $group); |
| |
| if (!defined($initiators)) { |
| my $rc = $self->groupExists($driver, $target, $group); |
| return FALSE if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| foreach my $_initiator (@{$initiators}) { |
| return TRUE if ($initiator eq $_initiator); |
| } |
| |
| return FALSE; |
| } |
| |
| sub lunExists { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $lun = shift; |
| my $group = shift; |
| |
| return FALSE if (!valid($driver, $target, $lun)); |
| |
| my ($luns, $errorString) = $self->luns($driver, $target, $group); |
| |
| if (!defined($luns)) { |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| if (defined($group)) { |
| my $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| } |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| foreach my $_lun (keys %{$luns}) { |
| return TRUE if ($lun == $_lun); |
| } |
| |
| return FALSE; |
| } |
| |
| sub addGroup { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| |
| return SCST_C_GRP_ADD_FAIL if (!valid($driver, $target, $group)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| SCST_MGMT_IO); |
| $cmd .= "create $group"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_EXISTS if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_GRP_ADD_FAIL; |
| } |
| |
| sub removeGroup { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| |
| return SCST_C_GRP_REM_FAIL if (!valid($driver, $target, $group)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| SCST_MGMT_IO); |
| $cmd .= "del $group"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_GRP_REM_FAIL; |
| } |
| |
| sub addDeviceGroup { |
| my $self = shift; |
| my $group = shift; |
| |
| return SCST_C_DEV_GRP_ADD_FAIL if (!valid($group)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_DEV_GROUP_DIR(), SCST_MGMT_IO); |
| $cmd .= "create $group"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return $rc == TRUE ? SCST_C_DEV_GRP_EXISTS : $rc > 1 ? $rc : |
| SCST_C_DEV_GRP_ADD_FAIL; |
| } |
| |
| sub removeDeviceGroup { |
| my $self = shift; |
| my $group = shift; |
| |
| return SCST_C_DEV_GRP_REM_FAIL if (!valid($group)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_DEV_GROUP_DIR(), SCST_MGMT_IO); |
| $cmd .= "del $group"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DEV_GRP_REM_FAIL; |
| } |
| |
| sub addDeviceGroupDevice { |
| my $self = shift; |
| my $group = shift; |
| my $device = shift; |
| my $dgroups; |
| my $errorString; |
| |
| return SCST_C_DGRP_ADD_DEV_FAIL if (!valid($group, $device)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_DEVICES, |
| SCST_MGMT_IO); |
| $cmd .= "add $device"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->deviceExists($device); |
| return SCST_C_DEV_NO_DEVICE if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->deviceGroupDeviceExists($group, $device); |
| return SCST_C_DGRP_DEVICE_EXISTS if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| # Check all device groups for this device |
| ($dgroups, $errorString) = $self->deviceGroups(); |
| foreach my $dgroup (@{$dgroups}) { |
| my $devs; |
| |
| ($devs, $errorString) = $self->deviceGroupDevices($dgroup); |
| foreach my $dev (@{$devs}) { |
| return SCST_C_DGRP_DEVICE_OTHER if ($dev eq $device); |
| } |
| } |
| |
| return SCST_C_DGRP_ADD_DEV_FAIL; |
| } |
| |
| sub addTargetGroup { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| |
| return SCST_C_DGRP_ADD_GRP_FAIL if (!valid($group, $tgroup)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, |
| SCST_MGMT_IO); |
| $cmd .= "add $tgroup"; |
| |
| my $bytes = - ENONENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetGroupExists($group, $tgroup); |
| return SCST_C_DGRP_GROUP_EXISTS if ($rc == TRUE); |
| return $rc > 1 ? $rc : SCST_C_DGRP_ADD_GRP_FAIL; |
| } |
| |
| sub addTargetGroupTarget { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| my $tgt = shift; |
| |
| return SCST_C_TGRP_ADD_TGT_FAIL |
| if (!valid($group, $tgroup, $tgt)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, |
| $tgroup, SCST_MGMT_IO); |
| $cmd .= "add $tgt"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetGroupExists($group, $tgroup); |
| return SCST_C_DGRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetGroupTargetExists($group, $tgroup, $tgt); |
| return $rc == TRUE ? SCST_C_TGRP_TGT_EXISTS : $rc > 1 ? $rc : SCST_C_TGRP_ADD_TGT_FAIL; |
| } |
| |
| sub removeDeviceGroupDevice { |
| my $self = shift; |
| my $group = shift; |
| my $device = shift; |
| |
| return SCST_C_DGRP_REM_DEV_FAIL if (!valid($group, $device)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_DEVICES, |
| SCST_MGMT_IO); |
| $cmd .= "del $device"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->deviceExists($device); |
| return SCST_C_DEV_NO_DEVICE if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->deviceGroupDeviceExists($group, $device); |
| return SCST_C_DGRP_NO_DEVICE if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DGRP_REM_DEV_FAIL; |
| } |
| |
| sub removeTargetGroup { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| |
| return SCST_C_DGRP_REM_GRP_FAIL if (!valid($group, $tgroup)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, |
| SCST_MGMT_IO); |
| $cmd .= "del $tgroup"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetGroupExists($group, $tgroup); |
| return SCST_C_DGRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DGRP_REM_GRP_FAIL; |
| } |
| |
| sub removeTargetGroupTarget { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| my $tgt = shift; |
| |
| return SCST_C_TGRP_REM_TGT_FAIL if (!valid($group, $tgroup, $tgt)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, |
| $tgroup, SCST_MGMT_IO); |
| $cmd .= "del $tgt"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetGroupExists($group, $tgroup); |
| return SCST_C_DGRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetGroupTargetExists($group, $tgroup, $tgt); |
| return SCST_C_TGRP_NO_TGT if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_TGRP_REM_TGT_FAIL; |
| } |
| |
| sub addInitiator { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $initiator = shift; |
| |
| return SCST_C_GRP_ADD_INI_FAIL |
| if (!valid($driver, $target, $group, $initiator)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| $group, SCST_INITIATORS, SCST_MGMT_IO); |
| $cmd .= "add $initiator"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| return SCST_C_GRP_REM_INI_FAIL |
| if (!valid($driver, $target, $initiator)); |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->initiatorExists($driver, $target, $group, $initiator); |
| return SCST_C_GRP_INI_EXISTS if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_GRP_ADD_INI_FAIL; |
| } |
| |
| sub removeInitiator { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $initiator = shift; |
| |
| return SCST_C_GRP_REM_INI_FAIL |
| if (!valid($driver, $target, $group, $initiator)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| $group, SCST_INITIATORS, SCST_MGMT_IO); |
| $cmd .= "del $initiator"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->initiatorExists($driver, $target, $group, $initiator); |
| return SCST_C_GRP_NO_INI if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_GRP_REM_INI_FAIL; |
| } |
| |
| sub moveInitiator { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $from = shift; |
| my $to = shift; |
| my $initiator = shift; |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| $from, SCST_INITIATORS, SCST_MGMT_IO); |
| $cmd .= "move $initiator $to"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $from); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $to); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->initiatorExists($driver, $target, $from, $initiator); |
| return SCST_C_GRP_NO_INI if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->initiatorExists($driver, $target, $to, $initiator); |
| return SCST_C_GRP_INI_EXISTS if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_GRP_MOV_INI_FAIL; |
| } |
| |
| sub clearInitiators { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| $group, SCST_INITIATORS, SCST_MGMT_IO); |
| $cmd .= "clear"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_GRP_CLR_INI_FAIL; |
| } |
| |
| sub addLun { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $device = shift; |
| my $lun = shift; |
| my $attributes = shift; |
| my $group = shift; |
| |
| my $err = valid($group) ? SCST_C_GRP_ADD_LUN_FAIL : |
| SCST_C_TGT_ADD_LUN_FAIL; |
| |
| return $err if (!valid($driver, $target, $device, $lun, $attributes)); |
| |
| my $o_string = ""; |
| foreach my $attribute (keys %{$attributes}) { |
| my $value = $$attributes{$attribute}; |
| $o_string .= "$attribute=$value;"; |
| } |
| |
| $o_string =~ s/\s$//; |
| |
| my ($path, $cmd); |
| if (valid($group)) { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, SCST_LUNS, SCST_MGMT_IO); |
| } else { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_LUNS, SCST_MGMT_IO); |
| } |
| |
| $cmd .= "add $device $lun $o_string"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| if (valid($group)) { |
| my $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| } |
| |
| my $rc = $self->lunExists($driver, $target, $lun, $group); |
| return (valid($group) ? SCST_C_GRP_LUN_EXISTS : |
| SCST_C_TGT_LUN_EXISTS) if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->deviceOpen($device); |
| return SCST_C_DEV_NO_DEVICE if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->checkLunCreateAttributes($driver, $target, $attributes, $group); |
| return SCST_C_LUN_BAD_ATTRIBUTES if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| return $err; |
| } |
| |
| sub removeLun { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $lun = shift; |
| my $group = shift; |
| |
| my $err = valid($group) ? SCST_C_GRP_REM_LUN_FAIL : |
| SCST_C_TGT_ADD_LUN_FAIL; |
| |
| return $err if (!valid($driver, $target, $lun)); |
| |
| my ($path, $cmd); |
| if (valid($group)) { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, SCST_LUNS, |
| SCST_MGMT_IO); |
| } else { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_LUNS, SCST_MGMT_IO); |
| } |
| $cmd .= "del $lun"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| if (valid($group)) { |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| } |
| |
| $rc = $self->lunExists($driver, $target, $lun, $group); |
| return (valid($group) ? SCST_C_GRP_NO_LUN : |
| SCST_C_TGT_NO_LUN) if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return $err; |
| } |
| |
| sub replaceLun { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $lun = shift; |
| my $device = shift; |
| my $attributes = shift; |
| my $group = shift; |
| |
| my $err; |
| |
| return TRUE if (!valid($lun)); |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| if (valid($group)) { |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $err = SCST_C_GRP_NO_LUN; |
| } else { |
| $err = SCST_C_TGT_NO_LUN; |
| } |
| |
| $rc = $self->lunExists($driver, $target, $lun, $group); |
| return $err if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->deviceOpen($device); |
| return SCST_C_DEV_NO_DEVICE if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->checkLunCreateAttributes($driver, $target, $attributes, $group); |
| return SCST_C_LUN_BAD_ATTRIBUTES if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| my ($luns, $errorString) = $self->luns($driver, $target, $group); |
| |
| return SCST_C_LUN_DEV_EXISTS if ($$luns{$lun} eq $device); |
| |
| my $o_string = ""; |
| foreach my $attribute (keys %{$attributes}) { |
| my $value = $$attributes{$attribute}; |
| $o_string .= "$attribute=$value;"; |
| } |
| |
| $o_string =~ s/\s$//; |
| |
| my ($path, $cmd); |
| if (defined($group)) { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, SCST_LUNS, |
| SCST_MGMT_IO); |
| } else { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_LUNS, SCST_MGMT_IO); |
| } |
| $cmd .= "replace $device $lun $o_string"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| return SCST_C_LUN_RPL_DEV_FAIL; |
| } |
| |
| sub clearLuns { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| |
| my $err = valid($group) ? SCST_C_GRP_CLR_LUN_FAIL : |
| SCST_C_TGT_CLR_LUN_FAIL; |
| |
| return $err if (!valid($driver, $target)); |
| |
| my ($path, $cmd); |
| if (valid($group)) { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, SCST_LUNS, |
| SCST_MGMT_IO); |
| } else { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_LUNS, SCST_MGMT_IO); |
| } |
| $cmd .= "clear"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| if (valid($group)) { |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| } |
| |
| return $err; |
| } |
| |
| sub deviceHandler { |
| my $self = shift; |
| my $device = shift; |
| |
| return undef if (!valid($device)); |
| |
| my $handler = readlink(make_path(SCST_DEVICES_DIR(), $device, |
| 'handler')); |
| $handler =~ s/.*\///; |
| return $handler; |
| } |
| |
| sub devices { |
| my $self = shift; |
| my $handler = shift; |
| my @devices; |
| |
| my $dHandle = new IO::Handle; |
| my $_path = !valid($handler) ? SCST_DEVICES_DIR() : |
| make_path(SCST_HANDLERS_DIR(), $handler); |
| if (!(opendir $dHandle, $_path)) { |
| return (undef, "devices(): Unable to read directory '$_path': $!"); |
| } |
| |
| foreach my $device (readdir($dHandle)) { |
| next if ($device eq '.' || $device eq '..'); |
| |
| my $isdev = (-d make_path(SCST_DEVICES_DIR(), $device)); |
| if ($isdev && (!valid($handler) || |
| $handler eq $self->deviceHandler($device))) { |
| push @devices, $device; |
| } |
| } |
| |
| close $dHandle; |
| |
| return (\@devices, undef); |
| } |
| |
| sub deviceOpen { |
| my $self = shift; |
| my $device = shift; |
| |
| return FALSE if (!valid($device)); |
| |
| my ($devices, $errorString) = $self->devices(); |
| |
| return SCST_C_FATAL_ERROR if (!valid($devices)); |
| |
| foreach my $_device (@{$devices}) { |
| return TRUE if ($device eq $_device); |
| } |
| |
| return FALSE; |
| } |
| |
| sub deviceAttributes { |
| my $self = shift; |
| my $device = shift; |
| my %attributes = ( ); |
| my $errorString; |
| my $dca; |
| |
| my $pHandle = new IO::Handle; |
| my $_path = make_path(SCST_DEVICES_DIR(), $device); |
| if (!(opendir $pHandle, $_path)) { |
| if ($self->deviceOpen($device) != TRUE) { |
| $errorString = "deviceAttributes(): Device '$device' is not open"; |
| } else { |
| $errorString = "deviceAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| ($dca, $errorString) = $self->deviceCreateAttributes($self->deviceHandler($device)); |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO || $attribute eq 'uevent'); |
| my $pPath = make_path(SCST_DEVICES_DIR(), $device, $attribute); |
| my $mode = (stat($pPath))[2]; |
| |
| if ($attribute eq 'exported') { |
| my $eHandle = new IO::Handle; |
| opendir $eHandle, make_path(SCST_DEVICES_DIR(), |
| $device, $attribute); |
| |
| foreach my $export (readdir($eHandle)) { |
| next if (($export eq '.') || ($export eq '..')); |
| |
| my $linked = readlink make_path($pPath, $export); |
| |
| my $t = SCST_TARGETS; |
| my $g = SCST_GROUPS; |
| my $l = SCST_LUNS; |
| my ($driver, $target, $group, $lun) = "" x 4; |
| |
| if ($linked =~ /^(\.\.\/)*$t\/([^\/]+)\/([^\/]+)\/$g\/([^\/]+)\/$l\/(\d+)$/) { |
| $driver = $2; |
| $target = $3; |
| $group = $4; |
| $lun = $5; |
| } elsif ($linked =~ /^(\.\.\/)*$t\/([^\/]+)\/([^\/]+)\/$l\/(\d+)$/) { |
| $driver = $2; |
| $target = $3; |
| $group = ""; |
| $lun = $4; |
| } else { |
| print("internal error: could not parse $linked\n"); |
| next; |
| } |
| next if ($driver eq 'copy_manager'); |
| $attributes{$attribute}->{'value'}->{$driver}->{$target}->{$group} = $lun; |
| } |
| if ($attributes{$attribute}->{'value'}) { |
| $attributes{$attribute}->{'static'} = TRUE; |
| } |
| close $eHandle; |
| } elsif ($attribute eq 'handler') { |
| my $linked = readlink $pPath; |
| |
| $linked =~ s/.*\///; |
| $attributes{$attribute}->{'static'} = TRUE; |
| $attributes{$attribute}->{'value'} = $linked; |
| } elsif ($attribute eq 'scsi_device') { |
| my $linked = readlink $pPath; |
| |
| $linked =~ s/.*\///; |
| $attributes{$attribute}->{'static'} = TRUE; |
| $attributes{$attribute}->{'value'} = $linked; |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if ($attribute eq 'cpu_mask' || |
| $attribute eq 'filename' || |
| $attribute eq 'threads_num' || |
| $attribute eq 'threads_pool_type' || |
| ($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "deviceAttributes(): Unable to read ". |
| "device attribute '$attribute': $!"); |
| } |
| |
| my ($value, $is_key) = split("\n", _sysread($io) , 2); |
| close $io; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| next if ($attribute eq SCST_MGMT_IO); |
| |
| if ($attribute eq 'type') { |
| my($type, $type_string) = split(/\s\-\s/, $value, 2); |
| $attributes{$attribute}->{'value'} = $type; |
| $attributes{'type_string'}->{'value'} = $type_string; |
| $attributes{'type_string'}->{'static'} = TRUE; |
| } else { |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub driverAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my %attributes = ( ); |
| my $errorString; |
| |
| my $pHandle = new IO::Handle; |
| my $_path = make_path(SCST_TARGETS_DIR(), $driver); |
| if (!(opendir $pHandle, $_path)) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "driverAttributes(): Driver '$driver' is not available"; |
| } else { |
| $errorString = "driverAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO); |
| my $pPath = make_path(SCST_TARGETS_DIR(), $driver, $attribute); |
| my $mode = (stat($pPath))[2]; |
| |
| if (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if (($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "driverAttributes(): Unable to read ". |
| "driver attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| next if ($attribute eq SCST_MGMT_IO); |
| |
| if ($attribute eq SCST_TRACE_IO) { |
| $attributes{$attribute}->{'value'} = $value; |
| my @possible; |
| $value = ''; |
| my $start = FALSE; |
| while (my $line = <$io>) { |
| $start = TRUE if ($line !~ /\[/); |
| $value .= $line if ($start); |
| } |
| $value =~ s/\n//g; |
| |
| if ($value =~ /\[(.*)\]/) { |
| $value = $1; |
| |
| foreach my $t (split(/\,/, $value)) { |
| $t =~ s/^\s+//; $t =~ s/\s+$//; |
| push @possible, $t; |
| } |
| } |
| $attributes{$attribute}->{'set'} = \@possible; |
| } else { |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| close $io; |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub setDriverAttribute { |
| my $self = shift; |
| my $driver = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if (!valid($attribute) || !defined($value)); |
| |
| my $path = make_path(SCST_TARGETS_DIR(), $driver, $attribute); |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $attribute = $value\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return setAttrFailed($path, $bytes, SCST_C_DRV_BAD_ATTRIBUTES, |
| SCST_C_DRV_ATTRIBUTE_STATIC, |
| SCST_C_DRV_SETATTR_FAIL); |
| } |
| |
| sub targetAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my %attributes = ( ); |
| my $errorString; |
| |
| return (undef, "Too few arguments") if (!valid($driver, $target)); |
| |
| my $pHandle = new IO::Handle; |
| my $_path = make_path(SCST_TARGETS_DIR(), $driver, $target); |
| if (!(opendir $pHandle, $_path)) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "targetAttributes(): Driver '$driver' is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "targetAttributes(): Target '$target' is not available"; |
| } else { |
| $errorString = "targetAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO || $attribute eq 'uevent'); |
| my $pPath = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| $attribute); |
| my $mode = (stat($pPath))[2]; |
| |
| if ($attribute eq 'host') { |
| my $linked = readlink($pPath); |
| |
| $linked =~ s/.*\///; |
| $attributes{$attribute}->{'static'} = TRUE; |
| $attributes{$attribute}->{'value'} = $linked; |
| } elsif ($driver eq 'scst_local' && $attribute eq 'sessions') { |
| my $_session_path = make_path($_path, $attribute); |
| my $pSessHandle = new IO::Handle; |
| if (!(opendir $pSessHandle, $_session_path)) { |
| return (undef, "targetAttributes(): Unable to read directory '$_session_path': $!"); |
| } |
| my $key = 0; |
| foreach my $e (readdir($pSessHandle)) { |
| next if ($e eq '.' || $e eq '..'); |
| $attributes{'session_name'}->{'keys'}->{$key}->{'value'} = $e; |
| $key++; |
| } |
| } elsif (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if ($attribute eq 'enabled' || |
| $attribute eq 'cpu_mask' || |
| ($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "targetAttributes(): Unable to read ". |
| "target attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| close $io; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| next if ($attribute eq SCST_MGMT_IO); |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub setTargetAttribute { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if (!valid($driver, $target, $attribute) || |
| !defined($value)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, $attribute); |
| $cmd = $value; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $cmd > $path\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return setAttrFailed($path, $bytes, SCST_C_TGT_BAD_ATTRIBUTES, |
| SCST_C_TGT_ATTRIBUTE_STATIC, |
| SCST_C_TGT_SETATTR_FAIL); |
| } |
| |
| sub groupAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my %attributes = ( ); |
| my $errorString; |
| |
| my $pHandle = new IO::Handle; |
| my $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| $group); |
| if (!(opendir $pHandle, $_path)) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "groupAttributes(): Driver '$driver' is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "groupAttributes(): Target '$target' is not available"; |
| } elsif ($self->groupExists($driver, $target, $group) != TRUE) { |
| $errorString = "groupAttributes(): Group '$group' does not exist"; |
| } else { |
| $errorString = "groupAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO); |
| my $pPath = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, $attribute); |
| my $mode = (stat($pPath))[2]; |
| |
| if (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if ($attribute eq 'cpu_mask' || |
| ($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "groupAttributes(): Unable to read ". |
| "group attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| close $io; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| next if ($attribute eq SCST_MGMT_IO); |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub setGroupAttribute { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if (!valid($attribute) || !defined($value)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| $group, $attribute); |
| $cmd .= $value; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $cmd > $path\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return setAttrFailed($path, $bytes, SCST_C_GRP_BAD_ATTRIBUTES, |
| SCST_C_GRP_ATTRIBUTE_STATIC, |
| SCST_C_GRP_SETATTR_FAIL); |
| } |
| |
| sub lunAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $lun = shift; |
| my $group = shift; |
| my $errorString; |
| my %attributes = ( ); |
| |
| my ($_path, $luncrattr); |
| |
| if (valid($group)) { |
| $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, SCST_LUNS, $lun); |
| ($luncrattr, $errorString) = |
| $self->lunCreateAttributes($driver, $target, $group); |
| } else { |
| $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_LUNS, $lun); |
| ($luncrattr, $errorString) = $self->lunCreateAttributes($driver, $target); |
| } |
| |
| my $pHandle = new IO::Handle; |
| if (!(opendir $pHandle, $_path)) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "lunAttributes(): Driver '$driver' is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "lunAttributes(): Target '$target' is not available"; |
| } elsif (valid($group) && |
| $self->groupExists($driver, $target, $group) != TRUE) { |
| $errorString = "lunAttributes(): Group '$group' does not exist"; |
| } elsif ($self->lunExists($driver, $target, $lun, $group) != TRUE) { |
| $errorString = "lunAttributes(): LUN '$lun' does not exist"; |
| } else { |
| $errorString = "lunAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO); |
| my $pPath = make_path($_path, $attribute); |
| my $mode = (stat($pPath))[2]; |
| |
| if ($attribute eq 'device') { |
| my $linked = readlink($pPath); |
| |
| $linked =~ s/.*\///; |
| $attributes{$attribute}->{'static'} = TRUE; |
| $attributes{$attribute}->{'value'} = $linked; |
| } elsif (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if (($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "lunAttributes(): Unable to read ". |
| "lun attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| close $io; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| next if ($attribute eq SCST_MGMT_IO); |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub setLunAttribute { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $lun = shift; |
| my $attribute = shift; |
| my $value = shift; |
| my $group = shift; |
| |
| return SCST_C_LUN_SETATTR_FAIL |
| if (!valid($driver, $target, $lun, $attribute) || !defined($value)); |
| |
| my $path; |
| |
| if (valid($group)) { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, SCST_LUNS, $lun, |
| $attribute); |
| } else { |
| $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_LUNS, $lun, $attribute); |
| } |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $attribute = $value\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| if (valid($group)) { |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| } |
| |
| $rc = $self->lunExists($driver, $target, $lun, $group); |
| return (valid($group) ? SCST_C_GRP_NO_LUN : |
| SCST_C_TGT_NO_LUN) if (!$rc); |
| return $rc if ($rc > 1); |
| |
| my ($attributes, $errorString) = $self->lunAttributes($driver, $target, $lun, $group); |
| |
| return SCST_C_LUN_BAD_ATTRIBUTES if (!defined($$attributes{$attribute})); |
| return SCST_C_LUN_ATTRIBUTE_STATIC if ($$attributes{$attribute}->{'static'}); |
| |
| return SCST_C_LUN_SETATTR_FAIL; |
| } |
| |
| sub initiatorAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $initiator = shift; |
| my %attributes = ( ); |
| my $errorString; |
| |
| my $pHandle = new IO::Handle; |
| my $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| $group, SCST_INITIATORS, $initiator); |
| if (!(opendir $pHandle, $_path)) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "initiatorAttributes(): Driver '$driver' is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "initiatorAttributes(): Target '$target' is not available"; |
| } elsif ($self->groupExists($driver, $target, $group) != TRUE) { |
| $errorString = "initiatorAttributes(): Group '$group' does not exist"; |
| } elsif ($self->initiatorExists($driver, $target, $group, $initiator) != TRUE) { |
| $errorString = "initiatorAttributes(): Initiator '$initiator' does not exist"; |
| } else { |
| $errorString = "initiatorAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO); |
| my $pPath = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, SCST_INITIATORS, |
| $initiator, $attribute); |
| my $mode = (stat($pPath))[2]; |
| if (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if (($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "initiatorAttributes(): Unable to read ". |
| "initiator attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| close $io; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| next if ($attribute eq SCST_MGMT_IO); |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub setInitiatorAttribute { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $initiator = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if (!valid($attribute) || !defined($value)); |
| |
| my $path = make_path(SCST_TARGETS_DIR(), $driver, $target, SCST_GROUPS, |
| $group, SCST_LUNS, $initiator, $attribute); |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $attribute = $value\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->initiatorExists($driver, $target, $group, $initiator); |
| return SCST_C_GRP_NO_INI if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_INI_SETATTR_FAIL; |
| } |
| |
| sub deviceGroupAttributes { |
| my $self = shift; |
| my $group = shift; |
| my %attributes = ( ); |
| my $errorString; |
| |
| my $pHandle = new IO::Handle; |
| my $_path = make_path(SCST_DEV_GROUP_DIR(), $group); |
| if (!(opendir $pHandle, $_path)) { |
| if ($self->deviceGroupExists($group) != TRUE) { |
| $errorString = "deviceGroupAttributes(): Device group '$group' does not exist"; |
| } else { |
| $errorString = "deviceGroupAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO); |
| my $pPath = make_path(SCST_DEV_GROUP_DIR(), $group, $attribute); |
| my $mode = (stat($pPath))[2]; |
| if (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if (($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "deviceGroupAttributes(): Unable to read ". |
| "device group attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| close $io; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| next if ($attribute eq SCST_MGMT_IO); |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub targetGroupAttributes { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| my %attributes = ( ); |
| my $errorString; |
| |
| my $pHandle = new IO::Handle; |
| my $_path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, $tgroup); |
| if (!(opendir $pHandle, $_path)) { |
| if ($self->deviceGroupExists($group) != TRUE) { |
| $errorString = "targetGroupAttributes(): Device group '$group' does not exist"; |
| } elsif ($self->targetGroupExists($group, $tgroup) != TRUE) { |
| $errorString = "targetGroupAttributes(): Target Group '$tgroup' does not exist"; |
| } else { |
| $errorString = "targetGroupAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO); |
| my $pPath = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, $tgroup, $attribute); |
| my $mode = (stat($pPath))[2]; |
| if (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if (($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "targetGroupAttributes(): Unable to read ". |
| "target group attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| close $io; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| next if ($attribute eq SCST_MGMT_IO); |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub targetGroupTargetAttributes { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| my $tgt = shift; |
| my $local_tgt = shift; |
| my %attributes = ( ); |
| my $errorString; |
| |
| my $pHandle = new IO::Handle; |
| my $_path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, $tgroup, $tgt); |
| if (-l $_path && !$local_tgt) { |
| return (\%attributes, undef); |
| } |
| |
| if (!(opendir $pHandle, $_path)) { |
| if ($self->deviceGroupExists($group) != TRUE) { |
| $errorString = "targetGroupTargetAttributes(): Device group '$group' does not exist"; |
| } elsif ($self->targetGroupExists($group, $tgroup) != TRUE) { |
| $errorString = "targetGroupTargetAttributes(): Target Group '$tgroup' does not exist"; |
| } elsif ($self->targetGroupTargetExists($group, $tgroup, $tgt) != TRUE) { |
| $errorString = "targetGroupTargetAttributes(): Target '$tgt' does not exist"; |
| } else { |
| $errorString = "targetGroupTargetAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO); |
| my $pPath = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, |
| $tgroup, $tgt, $attribute); |
| my $mode = (stat($pPath))[2]; |
| if (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if (($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "targetGroupTargetAttributes(): Unable to read ". |
| "target group target attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| close $io; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| next if ($attribute eq SCST_MGMT_IO); |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| } |
| } |
| |
| close $pHandle; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub setAluaAttribute { |
| my $self = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if (!valid($attribute) || !defined($value)); |
| |
| my $bytes = - ENOENT; |
| my $path = make_path(SCST_DEV_GROUP_DIR(), $attribute); |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $value > $path\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| return setAttrFailed($path, $bytes, SCST_C_ALUA_BAD_ATTRIBUTES, |
| SCST_C_ALUA_ATTRIBUTE_STATIC, |
| SCST_C_ALUA_SETATTR_FAIL); |
| } |
| |
| sub setDeviceGroupAttribute { |
| my $self = shift; |
| my $group = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if (!valid($attribute) || !defined($value)); |
| |
| my $bytes = - ENOENT; |
| my $path = make_path(SCST_DEV_GROUP_DIR(), $group, $attribute); |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $attribute = $value\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return setAttrFailed($path, $bytes, SCST_C_DGRP_BAD_ATTRIBUTES, |
| SCST_C_DGRP_ATTRIBUTE_STATIC, |
| SCST_C_DGRP_SETATTR_FAIL); |
| } |
| |
| sub setTargetGroupAttribute { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if !valid($group, $tgroup, $attribute) || !defined($value); |
| |
| my $bytes = - ENOENT; |
| my $path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, $tgroup, $attribute); |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $attribute = $value\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetGroupExists($group, $tgroup); |
| return SCST_C_DGRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return setAttrFailed($path, $bytes, SCST_C_TGRP_BAD_ATTRIBUTES, |
| SCST_C_TGRP_ATTRIBUTE_STATIC, |
| SCST_C_TGRP_SETATTR_FAIL); |
| } |
| |
| sub setTargetGroupTargetAttribute { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| my $tgt = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if (!valid($group, $tgroup, $tgt, $attribute) || |
| !defined($value)); |
| |
| my $bytes = - ENOENT; |
| my $path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, |
| $tgroup, $tgt, $attribute); |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $attribute = $value\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceGroupExists($group); |
| return SCST_C_DEV_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetGroupExists($group, $tgroup); |
| return SCST_C_DGRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetGroupTargetExists($group, $tgroup, $tgt); |
| return SCST_C_TGRP_NO_TGT if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return setAttrFailed($path, $bytes, SCST_C_TGRP_TGT_BAD_ATTR, |
| SCST_C_TGRP_TGT_ATTR_STATIC, |
| SCST_C_TGRP_TGT_SETATTR_FAIL); |
| } |
| |
| sub handlers { |
| my $self = shift; |
| my @handlers; |
| |
| my $hHandle = new IO::Handle; |
| my $_path = SCST_HANDLERS_DIR(); |
| if (!(opendir $hHandle, $_path)) { |
| return (undef, "handlers(): Unable to read directory '$_path': $!"); |
| } |
| |
| foreach my $handler (readdir($hHandle)) { |
| next if (($handler eq '.') || ($handler eq '..')); |
| |
| if (-d make_path(SCST_HANDLERS_DIR(), $handler)) { |
| push @handlers, $handler; |
| } |
| } |
| |
| close $hHandle; |
| |
| @handlers = sort(@handlers); |
| |
| return (\@handlers, undef); |
| } |
| |
| sub handlerExists { |
| my $self = shift; |
| my $handler = shift; |
| |
| return FALSE if (!valid($handler)); |
| |
| my ($handlers, $errorString) = $self->handlers(); |
| |
| return SCST_C_FATAL_ERROR if (!defined($handlers)); |
| |
| foreach my $_handler (@{$handlers}) { |
| return TRUE if ($handler eq $_handler); |
| } |
| |
| return FALSE; |
| } |
| |
| sub setHandlerAttribute { |
| my $self = shift; |
| my $handler = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| return TRUE if (!valid($attribute) || !defined($value)); |
| |
| my $bytes = - ENOENT; |
| my $path = make_path(SCST_HANDLERS_DIR(), $handler, $attribute); |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $path -> $attribute = $value\n"; |
| } else { |
| $value .= "\n"; |
| $bytes = _syswrite($io, $value, length($value)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->handlerExists($handler); |
| return SCST_C_HND_NO_HANDLER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return setAttrFailed($path, $bytes, SCST_C_HND_BAD_ATTRIBUTES, |
| SCST_C_HND_ATTRIBUTE_STATIC, |
| SCST_C_HND_SETATTR_FAIL); |
| } |
| |
| sub handlerAttributes { |
| my $self = shift; |
| my $handler = shift; |
| my %attributes = ( ); |
| my $errorString; |
| my $a; |
| |
| ($a, $errorString) = devices($self, $handler); |
| $attributes{'devices'}->{'value'} = $a; |
| |
| my $hHandle = new IO::Handle; |
| my $_path = make_path(SCST_HANDLERS_DIR(), $handler); |
| if (!(opendir $hHandle, $_path)) { |
| if ($self->handlerExists($handler) != TRUE) { |
| $errorString = "handlerAttributes(): Handler '$handler' is not available"; |
| } else { |
| $errorString = "handlerAttributes(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $attribute (readdir($hHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO || $attribute eq 'uevent' || |
| $attribute eq 'module'); |
| my $pPath = make_path(SCST_HANDLERS_DIR(), $handler, $attribute); |
| my $mode = (stat($pPath))[2]; |
| |
| my $is_static; |
| if (($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $path = make_path(SCST_HANDLERS_DIR(), $handler, $attribute); |
| |
| my $io = new IO::File $path, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "handlerAttributes(): Unable to read handler attribute ". |
| "'$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| |
| my $is_key = <$io>; |
| $is_key = $is_key && $is_key =~ /\[key\]/; |
| |
| my $key = 0; |
| if ($is_key) { |
| if ($attribute =~ /^([^\d]+)(\d+)$/) { |
| $attribute = $1; |
| $key = $2; |
| } |
| } |
| |
| if ($attribute eq SCST_MGMT_IO) { |
| $attributes{$attribute}->{'static'} = TRUE; |
| $attributes{$attribute}->{'value'} = $value; |
| next; |
| } |
| |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $attributes{$attribute}->{'static'} = FALSE; |
| $attributes{$attribute}->{'value'} = undef; |
| } elsif ($attribute eq SCST_TRACE_IO) { |
| $attributes{$attribute}->{'value'} = $value; |
| my @possible; |
| $value = ''; |
| my $start = FALSE; |
| while (my $line = <$io>) { |
| $start = TRUE if ($line !~ /\[/); |
| $value .= $line if ($start); |
| } |
| $value =~ s/\n//g; |
| |
| if ($value =~ /\[(.*)\]/) { |
| $value = $1; |
| |
| foreach my $t (split(/\,/, $value)) { |
| $t =~ s/^\s+//; $t =~ s/\s+$//; |
| push @possible, $t; |
| } |
| } |
| $attributes{$attribute}->{'set'} = \@possible; |
| } elsif ($attribute eq 'type') { |
| my($type, $type_string) = split(/\s\-\s/, $value, 2); |
| $attributes{$attribute}->{'value'} = $type; |
| $attributes{'type_string'}->{'value'} = $type_string; |
| $attributes{'type_string'}->{'static'} = TRUE; |
| } else { |
| if ($is_key) { |
| $attributes{$attribute}->{'keys'}->{$key}->{'value'} = $value; |
| } else { |
| $attributes{$attribute}->{'value'} = $value; |
| } |
| } |
| |
| $attributes{$attribute}->{'static'} = $is_static; |
| |
| close $io; |
| } |
| |
| close $hHandle; |
| |
| $attributes{'devices'}->{'static'} = TRUE; |
| |
| return (\%attributes, undef); |
| } |
| |
| sub deviceExists { |
| my $self = shift; |
| my $device = shift; |
| |
| my ($handlers, $errorString) = $self->handlers(); |
| |
| return SCST_C_FATAL_ERROR if (!defined($handlers)); |
| |
| foreach my $handler (@{$handlers}) { |
| return TRUE if $self->handlerDeviceExists($handler, $device); |
| } |
| |
| return FALSE; |
| } |
| |
| sub handlerDeviceExists { |
| my $self = shift; |
| my $handler = shift; |
| my $device = shift; |
| |
| my ($devices, $errorString) = $self->devicesByHandler($handler); |
| |
| if (!defined($devices)) { |
| my $rc = $self->handlerExists($handler); |
| return FALSE if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| foreach my $_device (@{$devices}) { |
| return TRUE if ($_device eq $device); |
| } |
| |
| return FALSE; |
| } |
| |
| sub devicesByHandler { |
| my $self = shift; |
| my $handler = shift; |
| my $errorString; |
| my $attributes; |
| |
| ($attributes, $errorString) = $self->handlerAttributes($handler); |
| if (!defined($attributes)) { |
| if ($self->handlerExists($handler) != TRUE) { |
| $errorString = "devicesByHandler(): Handler '$handler' is not available"; |
| } else { |
| $errorString = "devicesByHandler() failed"; |
| } |
| return (undef, $errorString); |
| } |
| |
| return (\@{$$attributes{'devices'}->{'value'}}, undef); |
| } |
| |
| sub checkDeviceCreateAttributes { |
| my $self = shift; |
| my $handler = shift; |
| my $check = shift; |
| |
| return FALSE if (!defined($check)); |
| |
| my ($available, $errorString) = $self->deviceCreateAttributes($handler); |
| |
| if (!defined($available)) { |
| my $rc = $self->handlerExists($handler); |
| return SCST_C_HND_NO_HANDLER if (!$rc); |
| return $rc if (!$rc > 1); |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| if (ref($check) eq 'HASH') { |
| foreach my $attribute (keys %{$check}) { |
| if (!defined($$available{$attribute})) { |
| return TRUE; |
| } |
| } |
| } else { |
| if (!defined($$available{$check})) { |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| sub deviceCreateAttributes { |
| my $self = shift; |
| my $handler = shift; |
| my $available; |
| my %attributes = ( ); |
| my $errorString; |
| |
| return (undef, "missing handler argument") if (!valid($handler)); |
| |
| my $io = new IO::File make_path(SCST_HANDLERS_DIR(), $handler, |
| SCST_MGMT_IO), O_RDONLY; |
| |
| if (!$io) { |
| if ($self->handlerExists($handler) != TRUE) { |
| $errorString = "deviceCreateAttributes(): Handler '$handler' ". |
| "is not available"; |
| } else { |
| $errorString = "deviceCreateAttributes(): Unable to open mgmt ". |
| "interface for handler '$handler': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| while (my $in = <$io>) { |
| if ($in =~ /^The following parameters available\:/) { |
| (undef, $available) = split(/\:/, $in, 2); |
| $available =~ s/\.$//; |
| } |
| } |
| close $io; |
| |
| if ($available) { |
| foreach my $attribute (split(/\,/, $available)) { |
| $attribute =~ s/^\s+//; |
| $attribute =~ s/\s+$//; |
| $attributes{$attribute} = ''; |
| } |
| } |
| |
| return (\%attributes, undef); |
| } |
| |
| sub openDevice { |
| my $self = shift; |
| my $handler = shift; |
| my $device = shift; |
| my $attributes = shift; |
| |
| return SCST_C_DEV_OPEN_FAIL |
| if (!valid($handler, $device, $attributes)); |
| |
| my $o_string = ""; |
| foreach my $attribute (keys %{$attributes}) { |
| my $value = $$attributes{$attribute}; |
| $o_string .= "$attribute=$value;"; |
| } |
| |
| $o_string =~ s/\s$//; |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_HANDLERS_DIR(), $handler, SCST_MGMT_IO); |
| $cmd .= "add_device $device $o_string"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $errno = $!; |
| |
| my $rc = $self->handlerExists($handler); |
| return SCST_C_HND_NO_HANDLER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->checkDeviceCreateAttributes($handler, $attributes); |
| return SCST_C_DEV_BAD_ATTRIBUTES if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->handlerDeviceExists($handler, $device); |
| return SCST_C_DEV_EXISTS if ($rc == TRUE); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_DEV_OPEN_FAIL if ($errno == EINVAL); |
| |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| sub closeDevice { |
| my $self = shift; |
| my $handler = shift; |
| my $device = shift; |
| |
| return SCST_C_DEV_CLOSE_FAIL if (!valid($handler, $device)); |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_HANDLERS_DIR(), $handler, SCST_MGMT_IO); |
| $cmd .= "del_device $device"; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $errno = $!; |
| |
| my $rc = $self->handlerExists($handler); |
| return SCST_C_HND_NO_HANDLER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->handlerDeviceExists($handler, $device); |
| return SCST_C_DEV_NO_DEVICE if ($rc != TRUE); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| sub setDeviceAttribute { |
| my $self = shift; |
| my $device = shift; |
| my $attribute = shift; |
| my $value = shift; |
| |
| my ($path, $cmd); |
| $path = make_path(SCST_DEVICES_DIR(), $device, $attribute); |
| $cmd .= $value; |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| if ($self->{'debug'}) { |
| print "DBG($$): $cmd > $path\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| |
| my $rc = $self->deviceOpen($device); |
| return SCST_C_DEV_NO_DEVICE if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return setAttrFailed($path, $bytes, SCST_C_DEV_BAD_ATTRIBUTES, |
| SCST_C_DEV_ATTRIBUTE_STATIC, |
| SCST_C_DEV_SETATTR_FAIL); |
| } |
| |
| sub checkTargetCreateAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $check = shift; |
| |
| return FALSE if (!defined($check)); |
| |
| my ($available, $errorString) = $self->targetCreateAttributes($driver); |
| |
| if (!defined($available)) { |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| if (ref($check) eq 'HASH') { |
| foreach my $attribute (keys %{$check}) { |
| if (!defined($$available{$attribute})) { |
| return TRUE; |
| } |
| } |
| } else { |
| if (!defined($$available{$check})) { |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| sub targetCreateAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $available; |
| my %attributes = ( ); |
| my $errorString; |
| |
| my $io = new IO::File make_path(SCST_TARGETS_DIR(), $driver, |
| SCST_MGMT_IO), O_RDONLY; |
| |
| if (!$io) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "targetCreateAttributes(): Driver '$driver' ". |
| "is not available"; |
| } else { |
| $errorString = "targetCreateAttributes(): Unable to open driver mgmt ". |
| "interface for driver '$driver': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| while (my $in = <$io>) { |
| if ($in =~ /^The following parameters available\:/) { |
| (undef, $available) = split(/\:/, $in, 2); |
| $available =~ s/\.$//; |
| } |
| } |
| close $io; |
| |
| if ($available) { |
| foreach my $attribute (split(/\,/, $available)) { |
| $attribute =~ s/^\s+//; |
| $attribute =~ s/\s+$//; |
| $attributes{$attribute} = ''; |
| } |
| } |
| |
| return (\%attributes, undef); |
| } |
| |
| sub enableTarget { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $enable = shift; |
| |
| $enable = TRUE if ($enable); |
| |
| return $self->setTargetAttribute($driver, $target, 'enabled', $enable); |
| } |
| |
| sub resyncDevice { |
| my $self = shift; |
| my $device = shift; |
| |
| return $self->setDeviceAttribute($device, 'resync_size', 1); |
| } |
| |
| sub setT10DeviceId { |
| my $self = shift; |
| my $device = shift; |
| my $t10_id = shift; |
| |
| return $self->setDeviceAttribute($device, 't10_dev_id', $t10_id); |
| } |
| |
| sub deviceGroupExists { |
| my $self = shift; |
| my $group = shift; |
| |
| my ($groups, $errorString) = $self->deviceGroups(); |
| |
| return SCST_C_FATAL_ERROR if (!defined($groups)); |
| |
| foreach my $_group (@{$groups}) { |
| return TRUE if ($group eq $_group); |
| } |
| |
| return FALSE; |
| } |
| |
| sub deviceGroupDeviceExists { |
| my $self = shift; |
| my $group = shift; |
| my $device = shift; |
| |
| my ($devices, $errorString) = $self->deviceGroupDevices($group); |
| |
| if (!defined($devices)) { |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| foreach my $_device (@{$devices}) { |
| return TRUE if ($device eq $_device); |
| } |
| |
| return FALSE; |
| } |
| |
| sub targetGroupExists { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| |
| my ($tgroups, $errorString) = $self->targetGroups($group); |
| |
| if (!defined($tgroups)) { |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| foreach my $_tgroup (@{$tgroups}) { |
| return TRUE if ($tgroup eq $_tgroup); |
| } |
| |
| return FALSE; |
| } |
| |
| sub targetGroupTargetExists { |
| my $self = shift; |
| my $group = shift; |
| my $tgroup = shift; |
| my $tgt = shift; |
| |
| my ($targets, $errorString) = $self->targetGroupTargets($group, $tgroup); |
| |
| if (!defined($targets)) { |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| foreach my $_tgt (@{$targets}) { |
| return TRUE if ($tgt eq $_tgt); |
| } |
| |
| return FALSE; |
| } |
| |
| sub checkLunCreateAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $check = shift; |
| my $group = shift; |
| |
| return FALSE if (!defined($check)); |
| |
| my ($available, $errorString) = $self->lunCreateAttributes($driver, $target, $group); |
| |
| if (!defined($available)) { |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| if ($group) { |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| } |
| |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| if (ref($check) eq 'HASH') { |
| foreach my $attribute (keys %{$check}) { |
| if (!defined($$available{$attribute})) { |
| return TRUE; |
| } |
| } |
| } else { |
| if (!defined($$available{$check})) { |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| sub lunCreateAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $available; |
| my %attributes = ( ); |
| my $errorString; |
| |
| my $_path; |
| |
| if (valid($group)) { |
| $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_GROUPS, $group, SCST_LUNS, |
| SCST_MGMT_IO); |
| } else { |
| $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_LUNS, SCST_MGMT_IO); |
| } |
| |
| my $io = new IO::File $_path, O_RDONLY; |
| |
| if (!$io) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "lunCreateAttributes(): Driver '$driver' ". |
| "is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "lunCreateAttributes(): Target '$target' ". |
| "is not available"; |
| } elsif (valid($group) && |
| $self->groupExists($driver, $target, $group) != TRUE) { |
| $errorString = "lunCreateAttributes(): Group '$group' ". |
| "does not exist"; |
| } else { |
| $errorString = "lunCreateAttributes(): Unable to open luns mgmt ". |
| "interface for group '$group': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| while (my $in = <$io>) { |
| if ($in =~ /^The following parameters available\:/) { |
| (undef, $available) = split(/\:/, $in, 2); |
| $available =~ s/\.$//; |
| } |
| } |
| close $io; |
| |
| if ($available) { |
| foreach my $attribute (split(/\,/, $available)) { |
| $attribute =~ s/^\s+//; |
| $attribute =~ s/\s+$//; |
| $attributes{$attribute} = ''; |
| } |
| } |
| return (\%attributes, undef); |
| } |
| |
| sub checkInitiatorCreateAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $check = shift; |
| |
| return FALSE if (!defined($check)); |
| |
| my ($available, $errorString) = $self->initiatorCreateAttributes($driver, $target, $group); |
| |
| if (!defined($available)) { |
| my $rc = $self->driverExists($driver); |
| return SCST_C_DRV_NO_DRIVER if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->targetExists($driver, $target); |
| return SCST_C_TGT_NO_TARGET if (!$rc); |
| return $rc if ($rc > 1); |
| |
| $rc = $self->groupExists($driver, $target, $group); |
| return SCST_C_GRP_NO_GROUP if (!$rc); |
| return $rc if ($rc > 1); |
| |
| return SCST_C_FATAL_ERROR; |
| } |
| |
| if (ref($check) eq 'HASH') { |
| foreach my $attribute (keys %{$check}) { |
| if (!defined($$available{$attribute})) { |
| return TRUE; |
| } |
| } |
| } else { |
| if (!defined($$available{$check})) { |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| sub initiatorCreateAttributes { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $group = shift; |
| my $available; |
| my %attributes = ( ); |
| my $errorString; |
| |
| my $io = new IO::File make_path(SCST_TARGETS_DIR(), $driver, |
| $target, SCST_GROUPS, $group, |
| SCST_INITIATORS, SCST_MGMT_IO), |
| O_RDONLY; |
| |
| if (!$io) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "initiatorCreateAttributes(): Driver '$driver' ". |
| "is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "initiatorCreateAttributes(): Target '$target' ". |
| "is not available"; |
| } elsif ($self->groupExists($driver, $target, $group) != TRUE) { |
| $errorString = "initiatorCreateAttributes(): Group '$group' ". |
| "does not exist"; |
| } else { |
| $errorString = "initiatorCreateAttributes(): Unable to open initiators mgmt ". |
| "interface for group '$group': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| while (my $in = <$io>) { |
| if ($in =~ /^The following parameters available\:/) { |
| (undef, $available) = split(/\:/, $in, 2); |
| $available =~ s/\.$//; |
| } |
| } |
| close $io; |
| |
| if ($available) { |
| foreach my $attribute (split(/\,/, $available)) { |
| $attribute =~ s/^\s+//; |
| $attribute =~ s/\s+$//; |
| $attributes{$attribute} = ''; |
| } |
| } |
| |
| return (\%attributes, undef); |
| } |
| |
| sub sessions { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my %_sessions; |
| my $errorString; |
| |
| return (undef, "Too few arguments") if (!valid($driver, $target)); |
| |
| my $sHandle = new IO::Handle; |
| my $_path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_SESSIONS); |
| if (!(opendir $sHandle, $_path)) { |
| if ($self->driverExists($driver) != TRUE) { |
| $errorString = "sessions(): Driver '$driver' ". |
| "is not available"; |
| } elsif ($self->targetExists($driver, $target) != TRUE) { |
| $errorString = "sessions(): Target '$target' ". |
| "is not available"; |
| } else { |
| $errorString = "sessions(): Unable to read directory '$_path': $!"; |
| } |
| return (undef, $errorString); |
| } |
| |
| foreach my $session (readdir($sHandle)) { |
| next if (($session eq '.') || ($session eq '..')); |
| my $pHandle = new IO::Handle; |
| my $sPath = make_path($_path, $session); |
| if (!(opendir $pHandle, $sPath)) { |
| return (undef, "sessions(): Unable to read directory '$_path': $!"); |
| } |
| |
| foreach my $attribute (readdir($pHandle)) { |
| next if ($attribute eq '.' || $attribute eq '..' || |
| $attribute eq SCST_MGMT_IO); |
| my $pPath = make_path($sPath, $attribute); |
| |
| if ($attribute eq 'luns') { |
| my $linked = readlink $pPath; |
| my $g = SCST_GROUPS; |
| my $l = SCST_LUNS; |
| if (defined($linked) && |
| $linked =~ /\.\.\/\.\.\/$g\/(.*)\/$l/) { |
| my $group = $1; |
| $_sessions{$session}->{$attribute} = |
| $self->luns($driver, $target, $group); |
| } |
| } else { |
| my $mode = (stat($pPath))[2]; |
| if (!$mode) { |
| $mode = 0; |
| } |
| if (-d $pPath) { |
| # Skip directories |
| } else { |
| if (!(($mode & S_IRUSR) >> 6)) { |
| $_sessions{$session}->{$attribute}->{'static'} = FALSE; |
| $_sessions{$session}->{$attribute}->{'value'} = undef; |
| } else { |
| my $is_static; |
| if (($mode & S_IWUSR) >> 6) { |
| $is_static = FALSE; |
| } else { |
| $is_static = TRUE; |
| } |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, |
| "sessions(): Unable to read ". |
| "session attribute '$attribute': $!"); |
| } |
| |
| my $value = <$io>; |
| $value = "" if (!defined($value)); |
| chomp $value; |
| close $io; |
| |
| $_sessions{$session}->{$attribute}->{'value'} = $value; |
| $_sessions{$session}->{$attribute}->{'static'} = $is_static; |
| } |
| } |
| } |
| } |
| close $pHandle; |
| } |
| close $sHandle; |
| |
| return (\%_sessions, undef); |
| } |
| |
| sub closeSession { |
| my $self = shift; |
| my $driver = shift; |
| my $target = shift; |
| my $session = shift; |
| |
| my ($sessions, $errorString) = $self->sessions($driver, $target); |
| |
| return SCST_C_NO_SESSION if (!defined($$sessions{$session})); |
| |
| # If it's not closable, silently return |
| return FALSE if (!defined($$sessions{$session}->{'force_close'})); |
| |
| my $path = make_path(SCST_TARGETS_DIR(), $driver, $target, |
| SCST_SESSIONS, $session, 'force_close'); |
| |
| my $bytes = - ENOENT; |
| my $io = new IO::File $path, O_WRONLY; |
| if ($io) { |
| my $cmd = "1"; |
| if ($self->{'debug'}) { |
| print "DBG($$): $cmd\n"; |
| } else { |
| $bytes = _syswrite($io, $cmd, length($cmd)); |
| } |
| close $io; |
| return FALSE if ($self->{'debug'} || $bytes > 0); |
| } |
| return SCST_C_SESSION_CLOSE_FAIL; |
| } |
| |
| sub sgvStats { |
| my $self = shift; |
| my %stats; |
| |
| my $sHandle = new IO::Handle; |
| my $_path = SCST_SGV_DIR(); |
| if (!(opendir $sHandle, $_path)) { |
| return (undef, "svgStats(): Unable to read directory '$_path': $!"); |
| } |
| |
| foreach my $stat (readdir($sHandle)) { |
| next if (($stat eq '.') || ($stat eq '..')); |
| |
| my $sPath = make_path(SCST_SGV_DIR(), $stat); |
| |
| if (-d $sPath) { |
| my $lHandle = new IO::Handle; |
| if (!(opendir $lHandle, $sPath)) { |
| return (undef, "svgStats(): Unable to read directory '$sPath': $!"); |
| } |
| |
| foreach my $lief (readdir($lHandle)) { |
| my $pPath = make_path($sPath, $lief); |
| |
| my $io = new IO::File $pPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "sgvStats(): Unable to read ". |
| "sgv stat '$stat/$lief': $!"); |
| } |
| |
| my $buffer; |
| while (my $value = <$io>) { |
| $buffer .= $value; |
| } |
| close $io; |
| |
| $stats{$stat}->{$lief} = $buffer; |
| } |
| close $lHandle; |
| } else { |
| my $io = new IO::File $sPath, O_RDONLY; |
| |
| if (!$io) { |
| return (undef, "sgvStats(): Unable to read ". |
| "sgv stat '$stat': $!"); |
| } |
| |
| my $buffer; |
| while (my $value = <$io>) { |
| $buffer .= $value; |
| } |
| close $io; |
| |
| $stats{$stat} = $buffer; |
| } |
| } |
| close $sHandle; |
| |
| return (\%stats, undef); |
| } |
| |
| sub errorString { |
| my $self = shift; |
| my $rc = shift; |
| |
| return defined($rc) ? $VERBOSE_ERROR{$rc} : undef; |
| } |
| |
| # Read from the SCST sysfs file $1. Return either the data read or undef if |
| # reading failed. |
| sub _sysread { |
| my $io = shift; |
| my $deadline = time() + $TIMEOUT; |
| my $result; |
| |
| while (time() < $deadline) { |
| my $bytes = sysread($io, $result, 4096); |
| last if (defined($bytes) || $! != EAGAIN); |
| sleep 1; |
| } |
| |
| return $result; |
| } |
| |
| # Write the first $3 bytes of $2 into the SCST sysfs file $1. Return either |
| # the number of bytes written or -errno if writing failed. |
| sub _syswrite { |
| my $io = shift; |
| my $cmd = shift; |
| my $length = shift; |
| my $now = time(); |
| |
| my $res_file = SCST_QUEUE_RES_PATH(); |
| |
| my $bytes = syswrite($io, $cmd, $length); |
| $bytes = -$! if (!defined($bytes)); |
| |
| if (defined($res_file) && $bytes == - EAGAIN) { |
| my $res_io = new IO::File $res_file, O_RDONLY; |
| |
| if (!$res_io) { |
| cluck("FATAL: Failed opening $res_file: $!"); |
| return - ENOENT; |
| } |
| |
| my $res_val; |
| |
| while (($now + $TIMEOUT) > time()) { |
| if (!defined(sysread($res_io, $res_val, 8)) && |
| $! == EAGAIN) { |
| sleep 1; |
| } else { |
| last; |
| } |
| } |
| |
| close $res_io; |
| |
| if (!defined($res_val)) { |
| my $_cmd = $cmd; chomp $_cmd; |
| cluck("Timeout while waiting for command '$_cmd' to complete"); |
| } elsif ($res_val == 0) { |
| $bytes = $length; |
| } |
| } |
| |
| return $bytes; |
| } |
| |
| sub make_path { |
| my $path; |
| |
| foreach my $element (@_) { |
| if ($path && rindex($path, '/') != length($path) - 1) { |
| $path .= '/'; |
| } |
| cluck("make_path: invalid argument") if !valid($element); |
| $path .= $element; |
| } |
| |
| return $path; |
| } |
| |
| ;1 __END__ |
| |
| =head1 NAME |
| |
| SCST::SCST - Generic SCST methods. |
| |
| =head1 SYNOPSIS |
| |
| use SCST::SCST; |
| |
| $p = SCST::SCST->new(); |
| |
| print "Using SCST version".$p->scstVersion()."\n"; |
| |
| undef $p; |
| |
| =head1 DESCRIPTION |
| |
| Generic SCST methods. |
| |
| =head2 Methods |
| |
| =over 5 |
| |
| =item SCST::SCST->new(); |
| |
| Create a new SCST object. If the argument $debug is non-zero no changes |
| will be made. |
| |
| Arguments: (bool) $debug |
| |
| Returns: (object) $new |
| |
| =item SCST::SCST->scstVersion(); |
| |
| Returns the version of SCST running. |
| |
| Arguments: void |
| |
| Returns: (string) $version |
| |
| =back |
| |
| =head1 WARNING |
| |
| None at this time. |
| |
| =head1 NOTES |
| |
| None at this time. |
| |
| =cut |