Add build system
[zfs.git] / scripts / common.sh.in
1 #!/bin/bash
2 #
3 # Common support functions for testing scripts.  If a .script-config
4 # files is available it will be sourced so in-tree kernel modules and
5 # utilities will be used.  If no .script-config can be found then the
6 # installed kernel modules and utilities will be used.
7
8 basedir="$(dirname $0)"
9
10 SCRIPT_CONFIG=.script-config
11 if [ -f "${basedir}/../${SCRIPT_CONFIG}" ]; then
12 . "${basedir}/../${SCRIPT_CONFIG}"
13 else
14 MODULES=(zlib_deflate spl splat zavl znvpair zunicode zcommon zfs)
15 fi
16
17 PROG="<define PROG>"
18 CLEANUP=
19 VERBOSE=
20 VERBOSE_FLAG=
21 FORCE=
22 FORCE_FLAG=
23 DUMP_LOG=
24 ERROR=
25 RAID0S=()
26 RAID10S=()
27 RAIDZS=()
28 RAIDZ2S=()
29
30 prefix=@prefix@
31 exec_prefix=@exec_prefix@
32 libexecdir=@libexecdir@
33 pkglibexecdir=${libexecdir}/@PACKAGE@
34 bindir=@bindir@
35 sbindir=@sbindir@
36
37 ETCDIR=${ETCDIR:-/etc}
38 DEVDIR=${DEVDIR:-/dev/disk/zpool}
39 ZPOOLDIR=${ZPOOLDIR:-${pkglibexecdir}/zpool-config}
40
41 ZDB=${ZDB:-${sbindir}/zdb}
42 ZFS=${ZFS:-${sbindir}/zfs}
43 ZINJECT=${ZINJECT:-${sbindir}/zinject}
44 ZPOOL=${ZPOOL:-${sbindir}/zpool}
45 ZPOOL_ID=${ZPOOL_ID:-${bindir}/zpool_id}
46 ZTEST=${ZTEST:-${sbindir}/ztest}
47
48 COMMON_SH=${COMMON_SH:-${pkglibexecdir}/common.sh}
49 ZFS_SH=${ZFS_SH:-${pkglibexecdir}/zfs.sh}
50 ZPOOL_CREATE_SH=${ZPOOL_CREATE_SH:-${pkglibexecdir}/zpool-create.sh}
51
52 LDMOD=${LDMOD:-/sbin/modprobe}
53 LSMOD=${LSMOD:-/sbin/lsmod}
54 RMMOD=${RMMOD:-/sbin/rmmod}
55 INFOMOD=${INFOMOD:-/sbin/modinfo}
56 LOSETUP=${LOSETUP:-/sbin/losetup}
57 SYSCTL=${SYSCTL:-/sbin/sysctl}
58 UDEVADM=${UDEVADM:-/sbin/udevadm}
59 AWK=${AWK:-/usr/bin/awk}
60
61 die() {
62         echo -e "${PROG}: $1" >&2
63         exit 1
64 }
65
66 msg() {
67         if [ ${VERBOSE} ]; then
68                 echo "$@"
69         fi
70 }
71
72 pass() {
73         echo "PASS"
74 }
75
76 fail() {
77         echo "FAIL ($1)"
78         exit $1
79 }
80
81 spl_dump_log() {
82         ${SYSCTL} -w kernel.spl.debug.dump=1 &>/dev/null
83         local NAME=`dmesg | tail -n 1 | cut -f5 -d' '`
84         ${SPLBUILD}/cmd/spl ${NAME} >${NAME}.log
85         echo
86         echo "Dumped debug log: ${NAME}.log"
87         tail -n1 ${NAME}.log
88         echo
89         return 0
90 }
91
92 check_modules() {
93         local LOADED_MODULES=()
94         local MISSING_MODULES=()
95
96         for MOD in ${MODULES[*]}; do
97                 local NAME=`basename $MOD .ko`
98
99                 if ${LSMOD} | egrep -q "^${NAME}"; then
100                         LOADED_MODULES=(${NAME} ${LOADED_MODULES[*]})
101                 fi
102
103                 if [ ${INFOMOD} ${MOD} 2>/dev/null ]; then
104                         MISSING_MODULES=("\t${MOD}\n" ${MISSING_MODULES[*]})
105                 fi
106         done
107
108         if [ ${#LOADED_MODULES[*]} -gt 0 ]; then
109                 ERROR="Unload these modules with '${PROG} -u':\n"
110                 ERROR="${ERROR}${LOADED_MODULES[*]}"
111                 return 1
112         fi
113
114         if [ ${#MISSING_MODULES[*]} -gt 0 ]; then
115                 ERROR="The following modules can not be found,"
116                 ERROR="${ERROR} ensure your source trees are built:\n"
117                 ERROR="${ERROR}${MISSING_MODULES[*]}"
118                 return 1
119         fi
120
121         return 0
122 }
123
124 load_module() {
125         local NAME=`basename $1 .ko`
126
127         if [ ${VERBOSE} ]; then
128                 echo "Loading ${NAME} ($@)"
129         fi
130
131         ${LDMOD} $* || ERROR="Failed to load $1" return 1
132
133         return 0
134 }
135
136 load_modules() {
137         mkdir -p /etc/zfs
138
139         for MOD in ${MODULES[*]}; do
140                 local NAME=`basename ${MOD} .ko`
141                 local VALUE=
142
143                 for OPT in "$@"; do
144                         OPT_NAME=`echo ${OPT} | cut -f1 -d'='`
145
146                         if [ ${NAME} = "${OPT_NAME}" ]; then
147                                 VALUE=`echo ${OPT} | cut -f2- -d'='`
148                         fi
149                 done
150
151                 load_module ${MOD} ${VALUE} || return 1
152         done
153
154         if [ ${VERBOSE} ]; then
155                 echo "Successfully loaded ZFS module stack"
156         fi
157
158         return 0
159 }
160
161 unload_module() {
162         local NAME=`basename $1 .ko`
163
164         if [ ${VERBOSE} ]; then
165                 echo "Unloading ${NAME} ($@)"
166         fi
167
168         ${RMMOD} ${NAME} || ERROR="Failed to unload ${NAME}" return 1
169
170         return 0
171 }
172
173 unload_modules() {
174         local MODULES_REVERSE=( $(echo ${MODULES[@]} |
175                 ${AWK} '{for (i=NF;i>=1;i--) printf $i" "} END{print ""}') )
176
177         for MOD in ${MODULES_REVERSE[*]}; do
178                 local NAME=`basename ${MOD} .ko`
179                 local USE_COUNT=`${LSMOD} |
180                                 egrep "^${NAME} "| ${AWK} '{print $3}'`
181
182                 if [ "${USE_COUNT}" = 0 ] ; then
183
184                         if [ "${DUMP_LOG}" -a ${NAME} = "spl" ]; then
185                                 spl_dump_log
186                         fi
187
188                         unload_module ${MOD} || return 1
189                 fi
190         done
191
192         if [ ${VERBOSE} ]; then
193                 echo "Successfully unloaded ZFS module stack"
194         fi
195
196         return 0
197 }
198
199 unused_loop_device() {
200         for DEVICE in `ls -1 /dev/loop*`; do
201                 ${LOSETUP} ${DEVICE} &>/dev/null
202                 if [ $? -ne 0 ]; then
203                         echo ${DEVICE}
204                         return
205                 fi
206         done
207
208         die "Error: Unable to find unused loopback device"
209 }
210
211 #
212 # This can be slightly dangerous because the loop devices we are
213 # cleanup up may not be ours.  However, if the devices are currently
214 # in use we will not be able to remove them, and we only remove
215 # devices which include 'zpool' in the name.  So any damage we might
216 # do should be limited to other zfs related testing.
217 #
218 cleanup_loop_devices() {
219         local TMP_FILE=`mktemp`
220
221         ${LOSETUP} -a | tr -d '()' >${TMP_FILE}
222         ${AWK} -F":" -v losetup="$LOSETUP" \
223             '/zpool/ { system("losetup -d "$1) }' ${TMP_FILE}
224         ${AWK} -F" " '/zpool/ { system("rm -f "$3) }' ${TMP_FILE}
225
226         rm -f ${TMP_FILE}
227 }
228
229 #
230 # The following udev helper functions assume that the provided
231 # udev rules file will create a /dev/disk/zpool/<CHANNEL><RANK>
232 # disk mapping.  In this mapping each CHANNEL is represented by
233 # the letters a-z, and the RANK is represented by the numbers
234 # 1-n.  A CHANNEL should identify a group of RANKS which are all
235 # attached to a single controller, each RANK represents a disk.
236 # This provides a simply mechanism to locate a specific drive
237 # given a known hardware configuration.
238 #
239 udev_setup() {
240         local SRC_PATH=$1
241
242         # When running in tree manually contruct symlinks in tree to
243         # the proper devices.  Symlinks are installed for all entires
244         # in the config file regardless of if that device actually
245         # exists.  When installed as a package udev can be relied on for
246         # this and it will only create links for devices which exist.
247         if [ ${INTREE} ]; then
248                 PWD=`pwd`
249                 mkdir -p ${DEVDIR}/
250                 cd ${DEVDIR}/
251                 ${AWK} '!/^#/ && /./ { system( \
252                         "ln -f -s /dev/disk/by-path/"$2" "$1";" \
253                         "ln -f -s /dev/disk/by-path/"$2"-part1 "$1"p1;" \
254                         "ln -f -s /dev/disk/by-path/"$2"-part9 "$1"p9;" \
255                         ) }' $SRC_PATH
256                 cd ${PWD}
257         else
258                 DST_FILE=`basename ${SRC_PATH} | cut -f1-2 -d'.'`
259                 DST_PATH=/etc/zfs/${DST_FILE}
260
261                 if [ -e ${DST_PATH} ]; then
262                         die "Error: Config ${DST_PATH} already exists"
263                 fi
264
265                 cp ${SRC_PATH} ${DST_PATH}
266
267                 if [ -f ${UDEVADM} ]; then
268                         ${UDEVADM} trigger
269                         ${UDEVADM} settle
270                 else
271                         /sbin/udevtrigger
272                         /sbin/udevsettle
273                 fi
274         fi
275
276         return 0
277 }
278
279 udev_cleanup() {
280         local SRC_PATH=$1
281
282         if [ ${INTREE} ]; then
283                 PWD=`pwd`
284                 cd ${DEVDIR}/
285                 ${AWK} '!/^#/ && /./ { system( \
286                         "rm -f "$1" "$1"p1 "$1"p9") }' $SRC_PATH
287                 cd ${PWD}
288         fi
289
290         return 0
291 }
292
293 udev_cr2d() {
294         local CHANNEL=`echo "obase=16; $1+96" | bc`
295         local RANK=$2
296
297         printf "\x${CHANNEL}${RANK}"
298 }
299
300 udev_raid0_setup() {
301         local RANKS=$1
302         local CHANNELS=$2
303         local IDX=0
304
305         RAID0S=()
306         for RANK in `seq 1 ${RANKS}`; do
307                 for CHANNEL in `seq 1 ${CHANNELS}`; do
308                         DISK=`udev_cr2d ${CHANNEL} ${RANK}`
309                         RAID0S[${IDX}]="${DEVDIR}/${DISK}"
310                         let IDX=IDX+1
311                 done
312         done
313
314         return 0
315 }
316
317 udev_raid10_setup() {
318         local RANKS=$1
319         local CHANNELS=$2
320         local IDX=0
321
322         RAID10S=()
323         for RANK in `seq 1 ${RANKS}`; do
324                 for CHANNEL1 in `seq 1 2 ${CHANNELS}`; do
325                         let CHANNEL2=CHANNEL1+1
326                         DISK1=`udev_cr2d ${CHANNEL1} ${RANK}`
327                         DISK2=`udev_cr2d ${CHANNEL2} ${RANK}`
328                         GROUP="${DEVDIR}/${DISK1} ${DEVDIR}/${DISK2}"
329                         RAID10S[${IDX}]="mirror ${GROUP}"
330                         let IDX=IDX+1
331                 done
332         done
333
334         return 0
335 }
336
337 udev_raidz_setup() {
338         local RANKS=$1
339         local CHANNELS=$2
340
341         RAIDZS=()
342         for RANK in `seq 1 ${RANKS}`; do
343                 RAIDZ=("raidz")
344
345                 for CHANNEL in `seq 1 ${CHANNELS}`; do
346                         DISK=`udev_cr2d ${CHANNEL} ${RANK}`
347                         RAIDZ[${CHANNEL}]="${DEVDIR}/${DISK}"
348                 done
349
350                 RAIDZS[${RANK}]="${RAIDZ[*]}"
351         done
352
353         return 0
354 }
355
356 udev_raidz2_setup() {
357         local RANKS=$1
358         local CHANNELS=$2
359
360         RAIDZ2S=()
361         for RANK in `seq 1 ${RANKS}`; do
362                 RAIDZ2=("raidz2")
363
364                 for CHANNEL in `seq 1 ${CHANNELS}`; do
365                         DISK=`udev_cr2d ${CHANNEL} ${RANK}`
366                         RAIDZ2[${CHANNEL}]="${DEVDIR}/${DISK}"
367                 done
368
369                 RAIDZ2S[${RANK}]="${RAIDZ2[*]}"
370         done
371
372         return 0
373 }