Skip to content

Commit b5dadcb

Browse files
committed
rescan-scsi-bus.sh: harden code
git-svn-id: svn://localhost/trunk@681 6180dd3e-e324-4e3e-922d-17de1ae2f315
1 parent bc2543a commit b5dadcb

File tree

4 files changed

+73
-27
lines changed

4 files changed

+73
-27
lines changed

CREDITS

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Andries Brouwer <aebr at win dot tue dot nl> rewrite of isosize (original
66
written by Joerg Schilling). isosize is now found in the util-linux
77
package and in the archive directory of this package.
88

9+
Bart Van Assche <bart dot vanassche at sandisk dot com>
10+
harden (improve) code in rescan-scsi-bus.sh [20160224]
11+
912
Brian Bunker <Brian dot Bunker at netapp dot com> contributed
1013
sg_read_block_limits and the target reset addition to sg_reset
1114
[20090615]
@@ -135,4 +138,4 @@ Trent Piepho <xyzzy at speakeasy dot org> print out some "sense key specific"
135138

136139

137140
Douglas Gilbert
138-
17th February 2015
141+
28th February 2016

ChangeLog

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ Each utility has its own version number, date of last change and
22
some description at the top of its ".c" file. All utilities in the main
33
directory have their own "man" pages. There is also a sg3_utils man page.
44

5-
Changelog for sg3_utils-1.43 [20160226] [svn: r680]
5+
Changelog for sg3_utils-1.43 [20160228] [svn: r681]
66
- sg_senddiag: add --timeout=SEC option
77
- sg_sanitize: add --timeout=SEC option
88
- sg_format: add --timeout=SEC option
99
- sg_reassign+sg_write_same: fix ULONG_MAX problem
1010
- sg_turs+sg_requests: make both accept '--num=NUM'
1111
and '--number=NUM' for mutual compatibility
12+
- rescan-scsi-bus.sh: harden code
1213
- shellcheck cleanup on scripts
1314

1415
Changelog for sg3_utils-1.42 [20160217] [svn: r663]

doc/sg3_utils.8

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ sg3_utils \- a package of utilities for sending SCSI commands
44
.SH SYNOPSIS
55
.B sg_*
66
[\fI\-\-enumerate\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-in=FN\fR]
7-
[\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
8-
[\fIOTHER_OPTIONS\fR]
7+
[\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-timeout=SEC\fR]
8+
[\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIOTHER_OPTIONS\fR]
99
\fIDEVICE\fR
1010
.SH DESCRIPTION
1111
.\" Add any additional description here
@@ -425,6 +425,28 @@ SCSI command, use this option. Alernatively the \fI\-\-in=FN\fR option causes
425425
from a file named \fIFN\fR. In these cases this option may indicate that
426426
binary data can be read from stdin or from a nominated file (e.g. \fIFN\fR).
427427
.TP
428+
\fB\-t\fR, \fB\-\-timeout\fR=\fISEC\fR
429+
utilities that issue potentially long\-running SCSI commands often have a
430+
\fI\-\-timeout=SEC\fR option. This typically instructs the operating system
431+
to abort the SCSI command in question once the timeout expires. Aborting
432+
SCSI commands is typically a messy business and in the case of format like
433+
commands may leave the device in a "format corrupt" state requiring another
434+
long\-running re\-initialization command to be sent. The argument, \fISEC\fR,
435+
is usually in seconds and the short form of the option may be something
436+
other than \fI\-t\fR since the timeout option was typically added later as
437+
storage devices grew in size and initialization commands took longer. Since
438+
many utilities had relatively long internal command timeouts before this
439+
option was introduced, the actual command timeout given to the operating
440+
systems is the higher of the internal timeout and \fISEC\fR.
441+
.br
442+
Many long running SCSI commands have an IMMED bit which causes the command
443+
to finish relatively quickly but the initialization process to continue. In
444+
such cases the REQUEST SENSE command can be used to monitor progress with
445+
its progress indication field (see the sg_requests and sg_turs utilities).
446+
Utilities that send such SCSI command either have an \fI\-\-immed\fR option
447+
or a \fI\-\-wait\fR option which is the logical inverse of the "immediate"
448+
action.
449+
.TP
428450
\fB\-v\fR, \fB\-\-verbose\fR
429451
increase the level of verbosity, (i.e. debug output). Can be used multiple
430452
times to further increase verbosity. The additional output is usually sent

scripts/rescan-scsi-bus.sh

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#!/bin/bash
2-
# Skript to rescan SCSI bus, using the
3-
# scsi add-single-device mechanism
2+
# Script to rescan SCSI bus, using the scsi add-single-device mechanism.
43
# (c) 1998--2010 Kurt Garloff <[email protected]>, GNU GPL v2 or v3
54
# (c) 2006--2015 Hannes Reinecke, GNU GPL v2 or later
65
# $Id: rescan-scsi-bus.sh,v 1.57 2012/03/31 14:08:48 garloff Exp $
76

8-
VERSION="20160201"
7+
VERSION="20160228"
98
SCAN_WILD_CARD=4294967295
109

1110
setcolor ()
@@ -44,11 +43,10 @@ print_and_scroll_back ()
4443
return $LN
4544
}
4645

47-
# Overwrite a text of length $1 (fallback to $LN) with whitespace
46+
# Overwrite a text of length $LN with whitespace
4847
white_out ()
4948
{
5049
BK=""; WH=""
51-
if test -n "$1"; then LN=$1; fi
5250
declare -i cntr=0
5351
while test $cntr -lt $LN; do BK="$BK\e[D"; WH="$WH "; let cntr+=1; done
5452
echo -en "$WH$BK"
@@ -91,8 +89,8 @@ findhosts ()
9189
if test $name = add_map -o $name = map -o $name = mod_parm; then continue; fi
9290
num=$name
9391
driverinfo=$driver
94-
if test -r $hostdir/status; then
95-
num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`)
92+
if test -r "$hostdir/status"; then
93+
num=$(printf '%d\n' "$(sed -n 's/SCSI host number://p' "$hostdir/status")")
9694
driverinfo="$driver:$name"
9795
fi
9896
hosts="$hosts $num"
@@ -168,17 +166,19 @@ $SCSITMP"
168166
fi
169167
else
170168
grepstr="scsi$host Channel: $CHANNEL Id: $ID Lun: $LUN"
171-
SCSISTR=`cat /proc/scsi/scsi | grep -A$LN -e"$grepstr"`
169+
SCSISTR=$(grep -A "$LN" -e "$grepstr" /proc/scsi/scsi)
172170
fi
173171
if test -z "$SCSISTR"; then return 1; else return 0; fi
174172
}
175173

176174
# Find sg device with 2.6 sysfs support
177175
sgdevice26 ()
178176
{
179-
if test -e /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic; then
180-
SGDEV=`readlink /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic`
181-
SGDEV=`basename $SGDEV`
177+
local gendev
178+
179+
gendev=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/generic
180+
if test -e "$gendev"; then
181+
SGDEV=$(basename "$(readlink "$gendev")")
182182
else
183183
for SGDEV in /sys/class/scsi_generic/sg*; do
184184
DEV=`readlink $SGDEV/device`
@@ -213,7 +213,7 @@ sgdevice ()
213213
DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null`
214214
if [ $? = 1 ]; then return; fi
215215
fi
216-
if ! `echo $DRV | grep 'drivers: sg' >/dev/null`; then
216+
if ! echo "$DRV" | grep -q 'drivers: sg'; then
217217
modprobe sg
218218
fi
219219
sgdevice24
@@ -223,14 +223,37 @@ sgdevice ()
223223
fi
224224
}
225225

226+
# Whether or not the RMB (removable) bit has been set in the INQUIRY response.
227+
# Uses ${host}, ${channel}, ${id} and ${lun}. Assumes that sg_device() has
228+
# already been called. How to test this function: copy/paste this function
229+
# in a shell and run
230+
# (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)
231+
is_removable ()
232+
{
233+
local b p
234+
235+
p=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/inquiry
236+
# Extract the second byte of the INQUIRY response and check bit 7 (mask 0x80).
237+
b=$(od -tx1 -j1 -N1 "$p" 2>/dev/null |
238+
{ read -r offset byte rest; echo -n "$byte"; })
239+
if [ -n "$b" ]; then
240+
echo $(((0x$b & 0x80) != 0))
241+
else
242+
sg_inq /dev/$SGDEV 2>/dev/null | sed -n 's/^.*RMB=\([0-9]*\).*$/\1/p'
243+
fi
244+
}
245+
226246
# Test if SCSI device is still responding to commands
227247
# Return values:
228248
# 0 device is present
229249
# 1 device has changed
230250
# 2 device has been removed
231251
testonline ()
232252
{
253+
local ctr RC RMB
254+
233255
: testonline
256+
ctr=0
234257
RC=0
235258
# Set default values
236259
IPTYPE=31
@@ -250,7 +273,7 @@ testonline ()
250273
RC=$?
251274
# Check for removable device; TEST UNIT READY obviously will
252275
# fail for a removable device with no medium
253-
RMB=`sg_inq /dev/$SGDEV 2>/dev/null | grep 'RMB=' | sed 's/^.*RMB=\(.\).*$/\1/'`
276+
RMB=$(is_removable)
254277
print_and_scroll_back "$host:$channel:$id:$lun $SGDEV ($RMB) "
255278
test $RC = 2 -a "$RMB" = "1" && break
256279
done
@@ -296,7 +319,7 @@ testonline ()
296319
return $RC
297320
}
298321

299-
# Test if SCSI device $host $channen $id $lun exists
322+
# Test if SCSI device $host $channel $id $lun exists
300323
# Outputs description from /proc/scsi/scsi (unless arg passed)
301324
# Returns SCSISTR (empty if no dev)
302325
testexist ()
@@ -382,7 +405,7 @@ getluns()
382405
if test $? != 0 -o -z "$LLUN"; then echo 0; return 1; fi
383406
for lun in $LLUN ; do
384407
# Swap LUN number
385-
l0=$(printf '%u' 0x$lun)
408+
l0=0x$lun
386409
l1=$(( ($l0 >> 48) & 0xffff ))
387410
l2=$(( ($l0 >> 32) & 0xffff ))
388411
l3=$(( ($l0 >> 16) & 0xffff ))
@@ -562,8 +585,7 @@ doreportlun()
562585
REPLUNSTAT=$?
563586
lunremove=
564587
#echo "getluns reports " $targetluns
565-
olddev=`find /sys/class/scsi_device/ -name $host:$channel:$id:* 2>/dev/null | sort -t: -k4 -n`
566-
oldluns=`echo "$olddev" | awk -F'/' '{print $5}' | awk -F':' '{print $4}'`
588+
olddev=`find /sys/class/scsi_device/ -name "$host:$channel:$id:*" 2>/dev/null | sort -t: -k4 -n`
567589
oldtargets="$targetluns"
568590
# OK -- if we don't have a LUN to send a REPORT_LUNS to, we could
569591
# fall back to wildcard scanning. Same thing if the device does not
@@ -577,7 +599,7 @@ doreportlun()
577599
else
578600
echo "scsi add-single-device $host $channel $id $SCAN_WILD_CARD" > /proc/scsi/scsi
579601
fi
580-
targetluns=`find /sys/class/scsi_device/ -name $host:$channel:$id:* 2>/dev/null | awk -F'/' '{print $5}' | awk -F':' '{print $4}' | sort -n`
602+
targetluns=`find /sys/class/scsi_device/ -name "$host:$channel:$id:*" 2>/dev/null | awk -F'/' '{print $5}' | awk -F':' '{print $4}' | sort -n`
581603
let found+=`echo "$targetluns" | wc -l`
582604
let found-=`echo "$olddev" | wc -l`
583605
fi
@@ -701,8 +723,6 @@ findremapped()
701723
local sddev=
702724
local id_serial=
703725
local id_serial_old=
704-
local sysfs_devpath=
705-
local mpath_uuid=
706726
local remapped=
707727
mpaths=""
708728
local tmpfile=$(mktemp /tmp/rescan-scsi-bus.XXXXXXXX 2> /dev/null)
@@ -862,13 +882,13 @@ findmultipath()
862882
local maj_min=`cat /sys/block/$dev/dev`
863883
for mp in $($DMSETUP ls --target=multipath | cut -f 1) ; do
864884
[ "$mp" = "No" ] && break;
865-
if $($DMSETUP status $mp | grep -q " $maj_min ") ; then
885+
if $DMSETUP status $mp | grep -q " $maj_min "; then
866886
# With two arguments, look up current uuid from sysfs
867887
# if it doesn't match what was passed, this multipath
868888
# device is not updated, so this is a remapped LUN
869889
if [ -n "$find_mismatch" ] ; then
870-
mp2=`$MULTIPATH -l $mp | egrep -o dm-[0-9]+`
871-
mp2=`cat /sys/block/$mp2/dm/uuid | cut -f2 -d-`
890+
mp2=$($MULTIPATH -l "$mp" | egrep -o "dm-[0-9]+")
891+
mp2=$(cut -f2 -d- "/sys/block/$mp2/dm/uuid")
872892
if [ "$find_mismatch" != "$mp2" ] ; then
873893
addmpathtolist $mp
874894
found_dup=1

0 commit comments

Comments
 (0)