OSDN Git Service

tests: try harder to clean up scsi_debug
[android-x86/external-parted.git] / tests / t-local.sh
1 # Put test-related bits that are parted-specific here.
2 # This file is sourced from the testing framework.
3 sector_size_=${PARTED_SECTOR_SIZE:-512}
4
5 scsi_debug_lock_dir_="$abs_srcdir/scsi_debug.lock"
6
7 require_scsi_debug_module_()
8 {
9   require_udevadm_settle_
10   # check for scsi_debug module
11   modprobe -n scsi_debug ||
12     skip_ "you lack the scsi_debug kernel module"
13 }
14
15 scsi_debug_modprobe_succeeded_=
16
17 # Always run this cleanup function.
18 cleanup_final_() { scsi_debug_cleanup_; }
19
20 scsi_debug_cleanup_()
21 {
22   # This function must always release the lock.
23   # If modprobe succeeded, it must be sure to run rmmod.
24   if test -n "$scsi_debug_modprobe_succeeded_"; then
25     # We have to insist.  Otherwise, a single rmmod usually fails to remove it,
26     # due either to "Resource temporarily unavailable" or to
27     # "Module scsi_debug is in use".
28     i=0
29     udevadm settle
30     while [ $i -lt 10 ] ; do
31       rmmod scsi_debug \
32         && { test "$VERBOSE" = yes && warn_ $ME_ rmmod scsi_debug...; break; }
33       sleep .2 || sleep 1
34       i=$((i + 1))
35     done
36     udevadm settle
37   fi
38   rm -fr $scsi_debug_lock_dir_
39 }
40
41 # Helper function: wait 2s (via .1s increments) for FILE to appear.
42 # Usage: wait_for_dev_to_appear_ /dev/sdg
43 # Return 0 upon success, 1 upon failure.
44 wait_for_dev_to_appear_()
45 {
46   local file=$1
47   local i=0
48   local incr=1
49   while :; do
50     ls "$file" > /dev/null 2>&1 && return 0
51     sleep .1 2>/dev/null || { sleep 1; incr=10; }
52     i=$(expr $i + $incr); test $i = 20 && break
53   done
54   return 1
55 }
56
57 # Tests that uses "modprobe scsi_debug ..." must not be run in parallel.
58 scsi_debug_acquire_lock_()
59 {
60   local retries=20
61   local lock_timeout_stale_seconds=120
62
63   # If it was created more than $lock_timeout_stale_seconds ago, remove it.
64   # FIXME: implement this
65
66   local i=0
67   local incr=1
68   while :; do
69     mkdir "$scsi_debug_lock_dir_" && return 0
70     sleep .1 2>/dev/null || { sleep 1; incr=10; }
71     i=$(expr $i + $incr); test $i = $(expr $retries \* 10) && break
72   done
73
74   warn_ "$ME_: failed to acquire lock: $scsi_debug_lock_dir_"
75   return 1
76 }
77
78 # If there is a scsi_debug device, print the corresponding "sdN" and return 0.
79 # Otherwise, return 1.
80 new_sdX_()
81 {
82   local m; m=$(grep -lw scsi_debug /sys/block/sd*/device/model) || return 1
83
84   # Remove the /sys/block/ prefix, and then the /device/model suffix.
85   m=${m#/sys/block/}
86   m=${m%/device/model}
87   echo "$m"
88   return 0
89 }
90
91 # Create a device using the scsi_debug module with the options passed to
92 # this function as arguments.  Upon success, print the name of the new device.
93 scsi_debug_setup_()
94 {
95   scsi_debug_acquire_lock_
96
97   # It is not trivial to determine the name of the device we're creating.
98   # Record the names of all /sys/block/sd* devices *before* probing:
99   touch stamp
100   modprobe scsi_debug "$@" || { rm -f stamp; return 1; }
101   scsi_debug_modprobe_succeeded_=1
102   test "$VERBOSE" = yes \
103     && warn_ $ME_ modprobe scsi_debug succeeded
104
105   # Wait up to 2s (via .1s increments) for the list of devices to change.
106   # Sleeping for a fraction of a second requires GNU sleep, so fall
107   # back on sleeping 2x1s if that fails.
108   # FIXME-portability: using "cmp - ..." probably requires GNU cmp.
109   local incr=1
110   local i=0
111   local new_dev
112   while :; do
113     new_dev=$(new_sdX_) && break
114     sleep .1 2>/dev/null || { sleep 1; incr=10; }
115     i=$(expr $i + $incr); test $i = 20 && break
116   done
117
118   case $new_dev in
119     sd[a-z]) ;;
120     sd[a-z][a-z]) ;;
121     *) warn_ $ME_ unexpected device name: $new_dev; return 1 ;;
122   esac
123   local t=/dev/$new_dev
124   wait_for_dev_to_appear_ $t
125   echo $t
126   return 0
127 }
128
129 require_512_byte_sector_size_()
130 {
131   test $sector_size_ = 512 \
132       || skip_ FS test with sector size != 512
133 }
134
135 peek_()
136 {
137   case $# in 2) ;; *) echo "usage: peek_ FILE 0_BASED_OFFSET" >&2; exit 1;; esac
138   case $2 in *[^0-9]*) echo "peek_: invalid offset: $2" >&2; exit 1 ;; esac
139   dd if="$1" bs=1 skip="$2" count=1
140 }
141
142 poke_()
143 {
144   case $# in 3) ;; *) echo "usage: poke_ FILE 0_BASED_OFFSET BYTE" >&2; exit 1;;
145     esac
146   case $2 in *[^0-9]*) echo "poke_: invalid offset: $2" >&2; exit 1 ;; esac
147   case $3 in ?) ;; *) echo "poke_: invalid byte: '$3'" >&2; exit 1 ;; esac
148   printf %s "$3" | dd of="$1" bs=1 seek="$2" count=1 conv=notrunc
149 }
150
151 # byte 56 of the partition entry is the first byte of its 72-byte name field
152 gpt1_pte_name_offset_()
153 {
154   local ss=$1
155   case $ss in *[^0-9]*) echo "$0: invalid sector size: $ss">&2; return 1;; esac
156   expr $ss \* 2 + 56
157   return 0
158 }
159
160 # Change the name of the first partition in the primary GPT table,
161 # thus invalidating the PartitionEntryArrayCRC32 checksum.
162 gpt_corrupt_primary_table_()
163 {
164   case $# in 2) ;; *) echo "$0: expected 2 args, got $#" >&2; return 1;; esac
165   local dev=$1
166   local ss=$2
167   case $ss in *[^0-9]*) echo "$0: invalid sector size: $ss">&2; return 1;; esac
168
169   # get the first byte of the name
170   local orig_pte_name_byte
171   orig_pte_name_byte=$(peek_ $dev $(gpt1_pte_name_offset_ $ss)) || return 1
172
173   local new_byte
174   test x"$orig_pte_name_byte" = xA && new_byte=B || new_byte=A
175
176   # Replace with a different byte
177   poke_ $dev $(gpt1_pte_name_offset_ $ss) "$new_byte" || return 1
178
179   printf %s "$orig_pte_name_byte"
180   return 0
181 }
182
183 gpt_restore_primary_table_()
184 {
185   case $# in 3) ;; *) echo "$0: expected 2 args, got $#" >&2; return 1;; esac
186   local dev=$1
187   local ss=$2
188   case $ss in *[^0-9]*) echo "$0: invalid sector size: $ss">&2; return 1;; esac
189   local orig_byte=$3
190   poke_ $dev $(gpt1_pte_name_offset_ $ss) "$orig_byte" || return 1
191 }
192
193 . "$abs_top_srcdir/tests/t-lvm.sh"