3 # Copyright (C) 2009 Chris Procter All rights reserved.
4 # Copyright (C) 2009 Red Hat, Inc. All rights reserved.
6 # This file is part of LVM2.
8 # This copyrighted material is made available to anyone wishing to use,
9 # modify, copy, or redistribute it subject to the terms and conditions
10 # of the GNU General Public License v.2.
12 # You should have received a copy of the GNU General Public License
13 # along with this program; if not, write to the Free Software Foundation,
14 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 # vgimportclone: This script is used to rename the VG and change the associated
17 # VG and PV UUIDs (primary application being HW snapshot restore)
19 # following external commands are used throughout the script
20 # echo and test are internal in bash at least
31 # user may override lvm location by setting LVM_BINARY
32 LVM
="${LVM_BINARY:-lvm}"
40 "$LVM" version
>& /dev
/null || die
2 "Could not run lvm binary '$LVM'"
44 ### get a unique vg name
45 ### $1 = list of exists VGs
46 ### $2 = the name we want
51 BNAME
="${NEWVG:-${VG}}"
55 while [[ "${VGLIST}" =~
"${NAME}" ]]
65 ### check return value and error if non zero
68 die
$1 "$2, error: $1"
74 ### display usage message
75 echo "Usage: ${SCRIPTNAME} [options] PhysicalVolume [PhysicalVolume...]"
76 echo " -n|--basevgname - Base name for the new volume group(s)"
77 echo " -i|--import - Import any exported volume groups found"
78 echo " -t|--test - Run in test mode"
79 echo " --quiet - Suppress output"
80 echo " -v|--verbose - Set verbose level"
81 echo " -d|--debug - Set debug level"
82 echo " --version - Display version information"
83 echo " -h|--help - Display this help message"
90 #set to use old lvm.conf
91 LVM_SYSTEM_DIR
=${ORIG_LVM_SYS_DIR}
93 if [ $KEEP_TMP_LVM_SYSTEM_DIR -eq 1 ]; then
94 echo "${SCRIPTNAME}: LVM_SYSTEM_DIR (${TMP_LVM_SYSTEM_DIR}) must be cleaned up manually."
96 "$RM" -rf -- "${TMP_LVM_SYSTEM_DIR}"
100 SCRIPTNAME
=`"$BASENAME" $0`
103 if [ "$UID" != "0" -a "$EUID" != "0" ]
105 die
3 "${SCRIPTNAME} must be run as root."
111 # for compatibility: using mktemp -t rather than --tmpdir
112 TMP_LVM_SYSTEM_DIR
=`"$MKTEMP" -d -t snap.XXXXXXXX`
113 KEEP_TMP_LVM_SYSTEM_DIR
=0
121 if [ -n "${LVM_SYSTEM_DIR}" ]; then
122 export ORIG_LVM_SYS_DIR
="${LVM_SYSTEM_DIR}"
125 trap cleanup
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
127 #####################################################################
128 ### Get and check arguments
129 #####################################################################
130 OPTIONS
=`"$GETOPT" -o n:dhitv \
131 -l basevgname:,debug,help,import,quiet,test,verbose,version \
132 -n "${SCRIPTNAME}" -- "$@"`
133 [ $?
-ne 0 ] && usage
134 eval set -- "$OPTIONS"
140 NEWVG
="$2"; shift; shift
150 LVM_OPTS
="--quiet ${LVM_OPTS}"
154 let VERBOSE_COUNT
=VERBOSE_COUNT
+1
159 VERBOSE
="${VERBOSE}v"
190 # turn on DEBUG (special case associated with -v use)
191 if [ -z "$DEBUG" -a $VERBOSE_COUNT -gt 3 ]; then
197 if [ -n "${DEBUG}" -o -n "${VERBOSE}" ]
199 LVM_OPTS
="${LVM_OPTS} ${DEBUG} ${VERBOSE}"
202 # process remaining arguments (which should be disks)
207 PVS_OUT
=`"${LVM}" pvs ${LVM_OPTS} --noheadings -o vg_name "$ARG" 2>/dev/null`
208 checkvalue $?
"$ARG is not a PV."
209 PV_VGNAME
=$
(echo $PVS_OUT |
$GREP -v '[[:space:]]+$')
210 [ -z "$PV_VGNAME" ] && die
3 "$ARG is not in a VG."
212 ln -s "$ARG" ${TMP_LVM_SYSTEM_DIR}/vgimport
${DEVNO}
213 DISKS
="${DISKS} ${TMP_LVM_SYSTEM_DIR}/vgimport${DEVNO}"
214 DEVNO
=$
((${DEVNO}+1))
216 die
3 "$ARG is not a block device."
220 ### check we have suitable values for important variables
226 #####################################################################
227 ### Get the existing state so we can use it later
228 #####################################################################
230 OLDVGS
=`"${LVM}" vgs ${LVM_OPTS} -o name --noheadings 2>/dev/null`
231 checkvalue $?
"Current VG names could not be collected without errors"
233 #####################################################################
234 ### Prepare the temporary lvm environment
235 #####################################################################
237 for BLOCK
in ${DISKS}
239 FILTER
="\"a|^${BLOCK}$|\", ${FILTER}"
241 export FILTER
="filter=[ ${FILTER} \"r|.*|\" ]"
243 LVMCONF
=${TMP_LVM_SYSTEM_DIR}/lvm.conf
245 "$LVM" dumpconfig
${LVM_OPTS} | \
246 "$AWK" -v DEV
=${TMP_LVM_SYSTEM_DIR} -v CACHE
=${TMP_LVM_SYSTEM_DIR}/.cache \
247 -v CACHE_DIR
=${TMP_LVM_SYSTEM_DIR}/cache \
248 '/^[[:space:]]*filter[[:space:]]*=/{print ENVIRON["FILTER"];next} \
249 /^[[:space:]]*scan[[:space:]]*=/{print "scan = [ \"" DEV "\" ]";next} \
250 /^[[:space:]]*cache[[:space:]]*=/{print "cache = \"" CACHE "\"";next} \
251 /^[[:space:]]*cache_dir[[:space:]]*=/{print "cache_dir = \"" CACHE_DIR "\"";next} \
252 {print $0}' > ${LVMCONF}
254 checkvalue $?
"Failed to generate ${LVMCONF}"
255 # Only keep TMP_LVM_SYSTEM_DIR if it contains something worth keeping
256 [ -n "${DEBUG}" ] && KEEP_TMP_LVM_SYSTEM_DIR
=1
258 # verify the config contains the filter, scan and cache_dir (or cache) config keywords
259 "$GREP" -q '^[[:space:]]*filter[[:space:]]*=' ${LVMCONF} || \
260 die
5 "Temporary lvm.conf must contain 'filter' config."
261 "$GREP" -q '^[[:space:]]*scan[[:space:]]*=' ${LVMCONF} || \
262 die
6 "Temporary lvm.conf must contain 'scan' config."
264 # check for either 'cache' or 'cache_dir' config values
265 "$GREP" -q '[[:space:]]*cache[[:space:]]*=' ${LVMCONF}
267 "$GREP" -q '^[[:space:]]*cache_dir' ${LVMCONF}
269 [ $CACHE_RET -eq 0 -o $CACHE_DIR_RET -eq 0 ] || \
270 die
7 "Temporary lvm.conf must contain 'cache' or 'cache_dir' config."
272 ### set to use new lvm.conf
273 export LVM_SYSTEM_DIR
=${TMP_LVM_SYSTEM_DIR}
276 #####################################################################
277 ### Rename the VG(s) and change the VG and PV UUIDs.
278 #####################################################################
280 PVINFO
=`"${LVM}" pvs ${LVM_OPTS} -o pv_name,vg_name,vg_attr --noheadings --separator : 2>/dev/null`
281 checkvalue $?
"PV info could not be collected without errors"
283 # output VG info so each line looks like: name:exported?:disk1,disk2,...
284 VGINFO
=`echo "${PVINFO}" | \
285 "$AWK" -F : '{{sub(/^[[:space:]]*/,"")} \
286 {sub(/unknown device/,"unknown_device")} \
287 {vg[$2]=$1","vg[$2]} if($3 ~ /^..x/){x[$2]="x"}} \
288 END{for(k in vg){printf("%s:%s:%s\n", k, x[k], vg[k])}}'`
289 checkvalue $?
"PV info could not be parsed without errors"
293 VGNAME
=`echo "${VG}" | "$CUT" -d: -f1`
294 EXPORTED
=`echo "${VG}" | "$CUT" -d: -f2`
295 PVLIST
=`echo "${VG}" | "$CUT" -d: -f3- | "$TR" , ' '`
297 if [ -z "${VGNAME}" ]
300 for DEV
in $PVLIST; do
301 FOLLOW
=`"$READLINK" $DEV`
302 FOLLOWLIST
="$FOLLOW $FOLLOWLIST"
304 die
8 "Specified PV(s) ($FOLLOWLIST) don't belong to a VG."
307 if [ -n "${EXPORTED}" ]
309 if [ ${IMPORT} -eq 1 ]
311 "$LVM" vgimport
${LVM_OPTS} ${TEST_OPT} "${VGNAME}"
312 checkvalue $? "Volume Group
${VGNAME} could not be imported
"
314 echo "Volume Group
${VGNAME} exported
, skipping.
"
319 ### change the pv uuids
320 if [[ "${PVLIST}" =~ "unknown
" ]]
322 echo "Volume Group
${VGNAME} has unknown PV
(s
), skipping.
"
323 echo "- Were all associated PV
(s
) supplied as arguments?
"
327 for BLOCKDEV in ${PVLIST}
329 "$LVM" pvchange ${LVM_OPTS} ${TEST_OPT} --uuid ${BLOCKDEV} --config 'global{activation=0}'
330 checkvalue $? "Unable to change PV uuid
for ${BLOCKDEV}"
333 NEWVGNAME=`getvgname "${OLDVGS}" "${VGNAME}" "${NEWVG}"`
335 "$LVM" vgchange ${LVM_OPTS} ${TEST_OPT} --uuid "${VGNAME}" --config 'global{activation=0}'
336 checkvalue $? "Unable to change VG uuid
for ${VGNAME}"
338 ## if the name isn't going to get changed dont even try.
339 if [ "${VGNAME}" != "${NEWVGNAME}" ]
341 "$LVM" vgrename ${LVM_OPTS} ${TEST_OPT} "${VGNAME}" "${NEWVGNAME}"
342 checkvalue $?
"Unable to rename ${VGNAME} to ${NEWVGNAME}"
348 #####################################################################
349 ### Restore the old environment
350 #####################################################################
351 ### set to use old lvm.conf
352 if [ -z "${ORIG_LVM_SYS_DIR}" ]
356 LVM_SYSTEM_DIR
=${ORIG_LVM_SYS_DIR}
359 ### update the device cache and make sure all
360 ### the device nodes we need are straight
361 if [ ${CHANGES_MADE} -eq 1 ]
363 "$LVM" vgscan
${LVM_OPTS} --mknodes