rescan-scsi-bus.sh: harden code
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@681 6180dd3e-e324-4e3e-922d-17de1ae2f315
diff --git a/CREDITS b/CREDITS
index a0082e2..f59ad04 100644
--- a/CREDITS
+++ b/CREDITS
@@ -6,6 +6,9 @@
written by Joerg Schilling). isosize is now found in the util-linux
package and in the archive directory of this package.
+Bart Van Assche <bart dot vanassche at sandisk dot com>
+ harden (improve) code in rescan-scsi-bus.sh [20160224]
+
Brian Bunker <Brian dot Bunker at netapp dot com> contributed
sg_read_block_limits and the target reset addition to sg_reset
[20090615]
@@ -135,4 +138,4 @@
Douglas Gilbert
-17th February 2015
+28th February 2016
diff --git a/ChangeLog b/ChangeLog
index 3910042..228946a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,13 +2,14 @@
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.43 [20160226] [svn: r680]
+Changelog for sg3_utils-1.43 [20160228] [svn: r681]
- sg_senddiag: add --timeout=SEC option
- sg_sanitize: add --timeout=SEC option
- sg_format: add --timeout=SEC option
- sg_reassign+sg_write_same: fix ULONG_MAX problem
- sg_turs+sg_requests: make both accept '--num=NUM'
and '--number=NUM' for mutual compatibility
+ - rescan-scsi-bus.sh: harden code
- shellcheck cleanup on scripts
Changelog for sg3_utils-1.42 [20160217] [svn: r663]
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index 914075a..bb80cd4 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -4,8 +4,8 @@
.SH SYNOPSIS
.B sg_*
[\fI\-\-enumerate\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-in=FN\fR]
-[\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
-[\fIOTHER_OPTIONS\fR]
+[\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-timeout=SEC\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIOTHER_OPTIONS\fR]
\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
@@ -425,6 +425,28 @@
from a file named \fIFN\fR. In these cases this option may indicate that
binary data can be read from stdin or from a nominated file (e.g. \fIFN\fR).
.TP
+\fB\-t\fR, \fB\-\-timeout\fR=\fISEC\fR
+utilities that issue potentially long\-running SCSI commands often have a
+\fI\-\-timeout=SEC\fR option. This typically instructs the operating system
+to abort the SCSI command in question once the timeout expires. Aborting
+SCSI commands is typically a messy business and in the case of format like
+commands may leave the device in a "format corrupt" state requiring another
+long\-running re\-initialization command to be sent. The argument, \fISEC\fR,
+is usually in seconds and the short form of the option may be something
+other than \fI\-t\fR since the timeout option was typically added later as
+storage devices grew in size and initialization commands took longer. Since
+many utilities had relatively long internal command timeouts before this
+option was introduced, the actual command timeout given to the operating
+systems is the higher of the internal timeout and \fISEC\fR.
+.br
+Many long running SCSI commands have an IMMED bit which causes the command
+to finish relatively quickly but the initialization process to continue. In
+such cases the REQUEST SENSE command can be used to monitor progress with
+its progress indication field (see the sg_requests and sg_turs utilities).
+Utilities that send such SCSI command either have an \fI\-\-immed\fR option
+or a \fI\-\-wait\fR option which is the logical inverse of the "immediate"
+action.
+.TP
\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output). Can be used multiple
times to further increase verbosity. The additional output is usually sent
diff --git a/scripts/rescan-scsi-bus.sh b/scripts/rescan-scsi-bus.sh
index e45caf3..80a9ae0 100755
--- a/scripts/rescan-scsi-bus.sh
+++ b/scripts/rescan-scsi-bus.sh
@@ -1,11 +1,10 @@
#!/bin/bash
-# Skript to rescan SCSI bus, using the
-# scsi add-single-device mechanism
+# Script to rescan SCSI bus, using the scsi add-single-device mechanism.
# (c) 1998--2010 Kurt Garloff <kurt@garloff.de>, GNU GPL v2 or v3
# (c) 2006--2015 Hannes Reinecke, GNU GPL v2 or later
# $Id: rescan-scsi-bus.sh,v 1.57 2012/03/31 14:08:48 garloff Exp $
-VERSION="20160201"
+VERSION="20160228"
SCAN_WILD_CARD=4294967295
setcolor ()
@@ -44,11 +43,10 @@
return $LN
}
-# Overwrite a text of length $1 (fallback to $LN) with whitespace
+# Overwrite a text of length $LN with whitespace
white_out ()
{
BK=""; WH=""
- if test -n "$1"; then LN=$1; fi
declare -i cntr=0
while test $cntr -lt $LN; do BK="$BK\e[D"; WH="$WH "; let cntr+=1; done
echo -en "$WH$BK"
@@ -91,8 +89,8 @@
if test $name = add_map -o $name = map -o $name = mod_parm; then continue; fi
num=$name
driverinfo=$driver
- if test -r $hostdir/status; then
- num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`)
+ if test -r "$hostdir/status"; then
+ num=$(printf '%d\n' "$(sed -n 's/SCSI host number://p' "$hostdir/status")")
driverinfo="$driver:$name"
fi
hosts="$hosts $num"
@@ -168,7 +166,7 @@
fi
else
grepstr="scsi$host Channel: $CHANNEL Id: $ID Lun: $LUN"
- SCSISTR=`cat /proc/scsi/scsi | grep -A$LN -e"$grepstr"`
+ SCSISTR=$(grep -A "$LN" -e "$grepstr" /proc/scsi/scsi)
fi
if test -z "$SCSISTR"; then return 1; else return 0; fi
}
@@ -176,9 +174,11 @@
# Find sg device with 2.6 sysfs support
sgdevice26 ()
{
- if test -e /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic; then
- SGDEV=`readlink /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic`
- SGDEV=`basename $SGDEV`
+ local gendev
+
+ gendev=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/generic
+ if test -e "$gendev"; then
+ SGDEV=$(basename "$(readlink "$gendev")")
else
for SGDEV in /sys/class/scsi_generic/sg*; do
DEV=`readlink $SGDEV/device`
@@ -213,7 +213,7 @@
DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null`
if [ $? = 1 ]; then return; fi
fi
- if ! `echo $DRV | grep 'drivers: sg' >/dev/null`; then
+ if ! echo "$DRV" | grep -q 'drivers: sg'; then
modprobe sg
fi
sgdevice24
@@ -223,6 +223,26 @@
fi
}
+# Whether or not the RMB (removable) bit has been set in the INQUIRY response.
+# Uses ${host}, ${channel}, ${id} and ${lun}. Assumes that sg_device() has
+# already been called. How to test this function: copy/paste this function
+# in a shell and run
+# (cd /sys/class/scsi_device && for d in *; do set ${d//:/ }; echo -n "$d $(</sys/class/scsi_device/${d}/device/block/*/removable) <> "; SGDEV=bsg/$d host=$1 channel=$2 id=$3 lun=$4 is_removable; done)
+is_removable ()
+{
+ local b p
+
+ p=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/inquiry
+ # Extract the second byte of the INQUIRY response and check bit 7 (mask 0x80).
+ b=$(od -tx1 -j1 -N1 "$p" 2>/dev/null |
+ { read -r offset byte rest; echo -n "$byte"; })
+ if [ -n "$b" ]; then
+ echo $(((0x$b & 0x80) != 0))
+ else
+ sg_inq /dev/$SGDEV 2>/dev/null | sed -n 's/^.*RMB=\([0-9]*\).*$/\1/p'
+ fi
+}
+
# Test if SCSI device is still responding to commands
# Return values:
# 0 device is present
@@ -230,7 +250,10 @@
# 2 device has been removed
testonline ()
{
+ local ctr RC RMB
+
: testonline
+ ctr=0
RC=0
# Set default values
IPTYPE=31
@@ -250,7 +273,7 @@
RC=$?
# Check for removable device; TEST UNIT READY obviously will
# fail for a removable device with no medium
- RMB=`sg_inq /dev/$SGDEV 2>/dev/null | grep 'RMB=' | sed 's/^.*RMB=\(.\).*$/\1/'`
+ RMB=$(is_removable)
print_and_scroll_back "$host:$channel:$id:$lun $SGDEV ($RMB) "
test $RC = 2 -a "$RMB" = "1" && break
done
@@ -296,7 +319,7 @@
return $RC
}
-# Test if SCSI device $host $channen $id $lun exists
+# Test if SCSI device $host $channel $id $lun exists
# Outputs description from /proc/scsi/scsi (unless arg passed)
# Returns SCSISTR (empty if no dev)
testexist ()
@@ -382,7 +405,7 @@
if test $? != 0 -o -z "$LLUN"; then echo 0; return 1; fi
for lun in $LLUN ; do
# Swap LUN number
- l0=$(printf '%u' 0x$lun)
+ l0=0x$lun
l1=$(( ($l0 >> 48) & 0xffff ))
l2=$(( ($l0 >> 32) & 0xffff ))
l3=$(( ($l0 >> 16) & 0xffff ))
@@ -562,8 +585,7 @@
REPLUNSTAT=$?
lunremove=
#echo "getluns reports " $targetluns
- olddev=`find /sys/class/scsi_device/ -name $host:$channel:$id:* 2>/dev/null | sort -t: -k4 -n`
- oldluns=`echo "$olddev" | awk -F'/' '{print $5}' | awk -F':' '{print $4}'`
+ olddev=`find /sys/class/scsi_device/ -name "$host:$channel:$id:*" 2>/dev/null | sort -t: -k4 -n`
oldtargets="$targetluns"
# OK -- if we don't have a LUN to send a REPORT_LUNS to, we could
# fall back to wildcard scanning. Same thing if the device does not
@@ -577,7 +599,7 @@
else
echo "scsi add-single-device $host $channel $id $SCAN_WILD_CARD" > /proc/scsi/scsi
fi
- targetluns=`find /sys/class/scsi_device/ -name $host:$channel:$id:* 2>/dev/null | awk -F'/' '{print $5}' | awk -F':' '{print $4}' | sort -n`
+ targetluns=`find /sys/class/scsi_device/ -name "$host:$channel:$id:*" 2>/dev/null | awk -F'/' '{print $5}' | awk -F':' '{print $4}' | sort -n`
let found+=`echo "$targetluns" | wc -l`
let found-=`echo "$olddev" | wc -l`
fi
@@ -701,8 +723,6 @@
local sddev=
local id_serial=
local id_serial_old=
- local sysfs_devpath=
- local mpath_uuid=
local remapped=
mpaths=""
local tmpfile=$(mktemp /tmp/rescan-scsi-bus.XXXXXXXX 2> /dev/null)
@@ -862,13 +882,13 @@
local maj_min=`cat /sys/block/$dev/dev`
for mp in $($DMSETUP ls --target=multipath | cut -f 1) ; do
[ "$mp" = "No" ] && break;
- if $($DMSETUP status $mp | grep -q " $maj_min ") ; then
+ if $DMSETUP status $mp | grep -q " $maj_min "; then
# With two arguments, look up current uuid from sysfs
# if it doesn't match what was passed, this multipath
# device is not updated, so this is a remapped LUN
if [ -n "$find_mismatch" ] ; then
- mp2=`$MULTIPATH -l $mp | egrep -o dm-[0-9]+`
- mp2=`cat /sys/block/$mp2/dm/uuid | cut -f2 -d-`
+ mp2=$($MULTIPATH -l "$mp" | egrep -o "dm-[0-9]+")
+ mp2=$(cut -f2 -d- "/sys/block/$mp2/dm/uuid")
if [ "$find_mismatch" != "$mp2" ] ; then
addmpathtolist $mp
found_dup=1