1 1.1 haad #!/bin/sh 2 1.1 haad 3 1.1 haad # Copyright (C) 2009 Chris Procter All rights reserved. 4 1.1 haad # Copyright (C) 2009 Red Hat, Inc. All rights reserved. 5 1.1 haad # 6 1.1 haad # This file is part of LVM2. 7 1.1 haad # 8 1.1 haad # This copyrighted material is made available to anyone wishing to use, 9 1.1 haad # modify, copy, or redistribute it subject to the terms and conditions 10 1.1 haad # of the GNU General Public License v.2. 11 1.1 haad # 12 1.1 haad # You should have received a copy of the GNU General Public License 13 1.1 haad # along with this program; if not, write to the Free Software Foundation, 14 1.1 haad # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 1.1 haad # 16 1.1 haad # vgimportclone: This script is used to rename the VG and change the associated 17 1.1 haad # VG and PV UUIDs (primary application being HW snapshot restore) 18 1.1 haad 19 1.1 haad # following external commands are used throughout the script 20 1.1 haad # echo and test are internal in bash at least 21 1.1 haad RM=rm 22 1.1 haad BASENAME=basename 23 1.1 haad MKTEMP=mktemp 24 1.1 haad AWK=awk 25 1.1 haad CUT=cut 26 1.1 haad TR=tr 27 1.1 haad READLINK=readlink 28 1.1 haad GREP=grep 29 1.1 haad GETOPT=getopt 30 1.1 haad 31 1.1 haad # user may override lvm location by setting LVM_BINARY 32 1.1 haad LVM="${LVM_BINARY:-lvm}" 33 1.1 haad 34 1.1 haad die() { 35 1.1 haad code=$1; shift 36 1.1 haad echo "Fatal: $@" 1>&2 37 1.1 haad exit $code 38 1.1 haad } 39 1.1 haad 40 1.1 haad "$LVM" version >& /dev/null || die 2 "Could not run lvm binary '$LVM'" 41 1.1 haad 42 1.1 haad 43 1.1 haad function getvgname { 44 1.1 haad ### get a unique vg name 45 1.1 haad ### $1 = list of exists VGs 46 1.1 haad ### $2 = the name we want 47 1.1 haad VGLIST=$1 48 1.1 haad VG=$2 49 1.1 haad NEWVG=$3 50 1.1 haad 51 1.1 haad BNAME="${NEWVG:-${VG}}" 52 1.1 haad NAME="${BNAME}" 53 1.1 haad I=0 54 1.1 haad 55 1.1 haad while [[ "${VGLIST}" =~ "${NAME}" ]] 56 1.1 haad do 57 1.1 haad I=$(($I+1)) 58 1.1 haad NAME="${BNAME}$I" 59 1.1 haad done 60 1.1 haad echo "${NAME}" 61 1.1 haad } 62 1.1 haad 63 1.1 haad 64 1.1 haad function checkvalue { 65 1.1 haad ### check return value and error if non zero 66 1.1 haad if [ $1 -ne 0 ] 67 1.1 haad then 68 1.1 haad die $1 "$2, error: $1" 69 1.1 haad fi 70 1.1 haad } 71 1.1 haad 72 1.1 haad 73 1.1 haad function usage { 74 1.1 haad ### display usage message 75 1.1 haad echo "Usage: ${SCRIPTNAME} [options] PhysicalVolume [PhysicalVolume...]" 76 1.1 haad echo " -n|--basevgname - Base name for the new volume group(s)" 77 1.1 haad echo " -i|--import - Import any exported volume groups found" 78 1.1 haad echo " -t|--test - Run in test mode" 79 1.1 haad echo " --quiet - Suppress output" 80 1.1 haad echo " -v|--verbose - Set verbose level" 81 1.1 haad echo " -d|--debug - Set debug level" 82 1.1 haad echo " --version - Display version information" 83 1.1 haad echo " -h|--help - Display this help message" 84 1.1 haad echo "" 85 1.1 haad exit 1 86 1.1 haad } 87 1.1 haad 88 1.1 haad 89 1.1 haad function cleanup { 90 1.1 haad #set to use old lvm.conf 91 1.1 haad LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR} 92 1.1 haad 93 1.1 haad if [ $KEEP_TMP_LVM_SYSTEM_DIR -eq 1 ]; then 94 1.1 haad echo "${SCRIPTNAME}: LVM_SYSTEM_DIR (${TMP_LVM_SYSTEM_DIR}) must be cleaned up manually." 95 1.1 haad else 96 1.1 haad "$RM" -rf -- "${TMP_LVM_SYSTEM_DIR}" 97 1.1 haad fi 98 1.1 haad } 99 1.1 haad 100 1.1 haad SCRIPTNAME=`"$BASENAME" $0` 101 1.1 haad 102 1.1 haad 103 1.1 haad if [ "$UID" != "0" -a "$EUID" != "0" ] 104 1.1 haad then 105 1.1 haad die 3 "${SCRIPTNAME} must be run as root." 106 1.1 haad fi 107 1.1 haad 108 1.1 haad LVM_OPTS="" 109 1.1 haad TEST_OPT="" 110 1.1 haad DISKS="" 111 1.1 haad # for compatibility: using mktemp -t rather than --tmpdir 112 1.1 haad TMP_LVM_SYSTEM_DIR=`"$MKTEMP" -d -t snap.XXXXXXXX` 113 1.1 haad KEEP_TMP_LVM_SYSTEM_DIR=0 114 1.1 haad CHANGES_MADE=0 115 1.1 haad IMPORT=0 116 1.1 haad DEBUG="" 117 1.1 haad VERBOSE="" 118 1.1 haad VERBOSE_COUNT=0 119 1.1 haad DEVNO=0 120 1.1 haad 121 1.1 haad if [ -n "${LVM_SYSTEM_DIR}" ]; then 122 1.1 haad export ORIG_LVM_SYS_DIR="${LVM_SYSTEM_DIR}" 123 1.1 haad fi 124 1.1 haad 125 1.1 haad trap cleanup 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 126 1.1 haad 127 1.1 haad ##################################################################### 128 1.1 haad ### Get and check arguments 129 1.1 haad ##################################################################### 130 1.1 haad OPTIONS=`"$GETOPT" -o n:dhitv \ 131 1.1 haad -l basevgname:,debug,help,import,quiet,test,verbose,version \ 132 1.1 haad -n "${SCRIPTNAME}" -- "$@"` 133 1.1 haad [ $? -ne 0 ] && usage 134 1.1 haad eval set -- "$OPTIONS" 135 1.1 haad 136 1.1 haad while true 137 1.1 haad do 138 1.1 haad case $1 in 139 1.1 haad -n|--basevgname) 140 1.1 haad NEWVG="$2"; shift; shift 141 1.1 haad ;; 142 1.1 haad -i|--import) 143 1.1 haad IMPORT=1; shift 144 1.1 haad ;; 145 1.1 haad -t|--test) 146 1.1 haad TEST_OPT="-t" 147 1.1 haad shift 148 1.1 haad ;; 149 1.1 haad --quiet) 150 1.1 haad LVM_OPTS="--quiet ${LVM_OPTS}" 151 1.1 haad shift 152 1.1 haad ;; 153 1.1 haad -v|--verbose) 154 1.1 haad let VERBOSE_COUNT=VERBOSE_COUNT+1 155 1.1 haad if [ -z "$VERBOSE" ] 156 1.1 haad then 157 1.1 haad VERBOSE="-v" 158 1.1 haad else 159 1.1 haad VERBOSE="${VERBOSE}v" 160 1.1 haad fi 161 1.1 haad shift 162 1.1 haad ;; 163 1.1 haad -d|--debug) 164 1.1 haad if [ -z "$DEBUG" ] 165 1.1 haad then 166 1.1 haad DEBUG="-d" 167 1.1 haad set -x 168 1.1 haad else 169 1.1 haad DEBUG="${DEBUG}d" 170 1.1 haad fi 171 1.1 haad shift 172 1.1 haad ;; 173 1.1 haad --version) 174 1.1 haad "$LVM" version 175 1.1 haad shift 176 1.1 haad exit 0 177 1.1 haad ;; 178 1.1 haad -h|--help) 179 1.1 haad usage; shift 180 1.1 haad ;; 181 1.1 haad --) 182 1.1 haad shift; break 183 1.1 haad ;; 184 1.1 haad *) 185 1.1 haad usage 186 1.1 haad ;; 187 1.1 haad esac 188 1.1 haad done 189 1.1 haad 190 1.1 haad # turn on DEBUG (special case associated with -v use) 191 1.1 haad if [ -z "$DEBUG" -a $VERBOSE_COUNT -gt 3 ]; then 192 1.1 haad DEBUG="-d" 193 1.1 haad set -x 194 1.1 haad fi 195 1.1 haad 196 1.1 haad # setup LVM_OPTS 197 1.1 haad if [ -n "${DEBUG}" -o -n "${VERBOSE}" ] 198 1.1 haad then 199 1.1 haad LVM_OPTS="${LVM_OPTS} ${DEBUG} ${VERBOSE}" 200 1.1 haad fi 201 1.1 haad 202 1.1 haad # process remaining arguments (which should be disks) 203 1.1 haad for ARG 204 1.1 haad do 205 1.1 haad if [ -b "$ARG" ] 206 1.1 haad then 207 1.1 haad PVS_OUT=`"${LVM}" pvs ${LVM_OPTS} --noheadings -o vg_name "$ARG" 2>/dev/null` 208 1.1 haad checkvalue $? "$ARG is not a PV." 209 1.1 haad PV_VGNAME=$(echo $PVS_OUT | $GREP -v '[[:space:]]+$') 210 1.1 haad [ -z "$PV_VGNAME" ] && die 3 "$ARG is not in a VG." 211 1.1 haad 212 1.1 haad ln -s "$ARG" ${TMP_LVM_SYSTEM_DIR}/vgimport${DEVNO} 213 1.1 haad DISKS="${DISKS} ${TMP_LVM_SYSTEM_DIR}/vgimport${DEVNO}" 214 1.1 haad DEVNO=$((${DEVNO}+1)) 215 1.1 haad else 216 1.1 haad die 3 "$ARG is not a block device." 217 1.1 haad fi 218 1.1 haad done 219 1.1 haad 220 1.1 haad ### check we have suitable values for important variables 221 1.1 haad if [ -z "${DISKS}" ] 222 1.1 haad then 223 1.1 haad usage 224 1.1 haad fi 225 1.1 haad 226 1.1 haad ##################################################################### 227 1.1 haad ### Get the existing state so we can use it later 228 1.1 haad ##################################################################### 229 1.1 haad 230 1.1 haad OLDVGS=`"${LVM}" vgs ${LVM_OPTS} -o name --noheadings 2>/dev/null` 231 1.1 haad checkvalue $? "Current VG names could not be collected without errors" 232 1.1 haad 233 1.1 haad ##################################################################### 234 1.1 haad ### Prepare the temporary lvm environment 235 1.1 haad ##################################################################### 236 1.1 haad 237 1.1 haad for BLOCK in ${DISKS} 238 1.1 haad do 239 1.1 haad FILTER="\"a|^${BLOCK}$|\", ${FILTER}" 240 1.1 haad done 241 1.1 haad export FILTER="filter=[ ${FILTER} \"r|.*|\" ]" 242 1.1 haad 243 1.1 haad LVMCONF=${TMP_LVM_SYSTEM_DIR}/lvm.conf 244 1.1 haad 245 1.1 haad "$LVM" dumpconfig ${LVM_OPTS} | \ 246 1.1 haad "$AWK" -v DEV=${TMP_LVM_SYSTEM_DIR} -v CACHE=${TMP_LVM_SYSTEM_DIR}/.cache \ 247 1.1 haad -v CACHE_DIR=${TMP_LVM_SYSTEM_DIR}/cache \ 248 1.1 haad '/^[[:space:]]*filter[[:space:]]*=/{print ENVIRON["FILTER"];next} \ 249 1.1 haad /^[[:space:]]*scan[[:space:]]*=/{print "scan = [ \"" DEV "\" ]";next} \ 250 1.1 haad /^[[:space:]]*cache[[:space:]]*=/{print "cache = \"" CACHE "\"";next} \ 251 1.1 haad /^[[:space:]]*cache_dir[[:space:]]*=/{print "cache_dir = \"" CACHE_DIR "\"";next} \ 252 1.1 haad {print $0}' > ${LVMCONF} 253 1.1 haad 254 1.1 haad checkvalue $? "Failed to generate ${LVMCONF}" 255 1.1 haad # Only keep TMP_LVM_SYSTEM_DIR if it contains something worth keeping 256 1.1 haad [ -n "${DEBUG}" ] && KEEP_TMP_LVM_SYSTEM_DIR=1 257 1.1 haad 258 1.1 haad # verify the config contains the filter, scan and cache_dir (or cache) config keywords 259 1.1 haad "$GREP" -q '^[[:space:]]*filter[[:space:]]*=' ${LVMCONF} || \ 260 1.1 haad die 5 "Temporary lvm.conf must contain 'filter' config." 261 1.1 haad "$GREP" -q '^[[:space:]]*scan[[:space:]]*=' ${LVMCONF} || \ 262 1.1 haad die 6 "Temporary lvm.conf must contain 'scan' config." 263 1.1 haad 264 1.1 haad # check for either 'cache' or 'cache_dir' config values 265 1.1 haad "$GREP" -q '[[:space:]]*cache[[:space:]]*=' ${LVMCONF} 266 1.1 haad CACHE_RET=$? 267 1.1 haad "$GREP" -q '^[[:space:]]*cache_dir' ${LVMCONF} 268 1.1 haad CACHE_DIR_RET=$? 269 1.1 haad [ $CACHE_RET -eq 0 -o $CACHE_DIR_RET -eq 0 ] || \ 270 1.1 haad die 7 "Temporary lvm.conf must contain 'cache' or 'cache_dir' config." 271 1.1 haad 272 1.1 haad ### set to use new lvm.conf 273 1.1 haad export LVM_SYSTEM_DIR=${TMP_LVM_SYSTEM_DIR} 274 1.1 haad 275 1.1 haad 276 1.1 haad ##################################################################### 277 1.1 haad ### Rename the VG(s) and change the VG and PV UUIDs. 278 1.1 haad ##################################################################### 279 1.1 haad 280 1.1 haad PVINFO=`"${LVM}" pvs ${LVM_OPTS} -o pv_name,vg_name,vg_attr --noheadings --separator : 2>/dev/null` 281 1.1 haad checkvalue $? "PV info could not be collected without errors" 282 1.1 haad 283 1.1 haad # output VG info so each line looks like: name:exported?:disk1,disk2,... 284 1.1 haad VGINFO=`echo "${PVINFO}" | \ 285 1.1 haad "$AWK" -F : '{{sub(/^[[:space:]]*/,"")} \ 286 1.1 haad {sub(/unknown device/,"unknown_device")} \ 287 1.1 haad {vg[$2]=$1","vg[$2]} if($3 ~ /^..x/){x[$2]="x"}} \ 288 1.1 haad END{for(k in vg){printf("%s:%s:%s\n", k, x[k], vg[k])}}'` 289 1.1 haad checkvalue $? "PV info could not be parsed without errors" 290 1.1 haad 291 1.1 haad for VG in ${VGINFO} 292 1.1 haad do 293 1.1 haad VGNAME=`echo "${VG}" | "$CUT" -d: -f1` 294 1.1 haad EXPORTED=`echo "${VG}" | "$CUT" -d: -f2` 295 1.1 haad PVLIST=`echo "${VG}" | "$CUT" -d: -f3- | "$TR" , ' '` 296 1.1 haad 297 1.1 haad if [ -z "${VGNAME}" ] 298 1.1 haad then 299 1.1 haad FOLLOWLIST="" 300 1.1 haad for DEV in $PVLIST; do 301 1.1 haad FOLLOW=`"$READLINK" $DEV` 302 1.1 haad FOLLOWLIST="$FOLLOW $FOLLOWLIST" 303 1.1 haad done 304 1.1 haad die 8 "Specified PV(s) ($FOLLOWLIST) don't belong to a VG." 305 1.1 haad fi 306 1.1 haad 307 1.1 haad if [ -n "${EXPORTED}" ] 308 1.1 haad then 309 1.1 haad if [ ${IMPORT} -eq 1 ] 310 1.1 haad then 311 1.1 haad "$LVM" vgimport ${LVM_OPTS} ${TEST_OPT} "${VGNAME}" 312 1.1 haad checkvalue $? "Volume Group ${VGNAME} could not be imported" 313 1.1 haad else 314 1.1 haad echo "Volume Group ${VGNAME} exported, skipping." 315 1.1 haad continue 316 1.1 haad fi 317 1.1 haad fi 318 1.1 haad 319 1.1 haad ### change the pv uuids 320 1.1 haad if [[ "${PVLIST}" =~ "unknown" ]] 321 1.1 haad then 322 1.1 haad echo "Volume Group ${VGNAME} has unknown PV(s), skipping." 323 1.1 haad echo "- Were all associated PV(s) supplied as arguments?" 324 1.1 haad continue 325 1.1 haad fi 326 1.1 haad 327 1.1 haad for BLOCKDEV in ${PVLIST} 328 1.1 haad do 329 1.1 haad "$LVM" pvchange ${LVM_OPTS} ${TEST_OPT} --uuid ${BLOCKDEV} --config 'global{activation=0}' 330 1.1 haad checkvalue $? "Unable to change PV uuid for ${BLOCKDEV}" 331 1.1 haad done 332 1.1 haad 333 1.1 haad NEWVGNAME=`getvgname "${OLDVGS}" "${VGNAME}" "${NEWVG}"` 334 1.1 haad 335 1.1 haad "$LVM" vgchange ${LVM_OPTS} ${TEST_OPT} --uuid "${VGNAME}" --config 'global{activation=0}' 336 1.1 haad checkvalue $? "Unable to change VG uuid for ${VGNAME}" 337 1.1 haad 338 1.1 haad ## if the name isn't going to get changed dont even try. 339 1.1 haad if [ "${VGNAME}" != "${NEWVGNAME}" ] 340 1.1 haad then 341 1.1 haad "$LVM" vgrename ${LVM_OPTS} ${TEST_OPT} "${VGNAME}" "${NEWVGNAME}" 342 1.1 haad checkvalue $? "Unable to rename ${VGNAME} to ${NEWVGNAME}" 343 1.1 haad fi 344 1.1 haad 345 1.1 haad CHANGES_MADE=1 346 1.1 haad done 347 1.1 haad 348 1.1 haad ##################################################################### 349 1.1 haad ### Restore the old environment 350 1.1 haad ##################################################################### 351 1.1 haad ### set to use old lvm.conf 352 1.1 haad if [ -z "${ORIG_LVM_SYS_DIR}" ] 353 1.1 haad then 354 1.1 haad unset LVM_SYSTEM_DIR 355 1.1 haad else 356 1.1 haad LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR} 357 1.1 haad fi 358 1.1 haad 359 1.1 haad ### update the device cache and make sure all 360 1.1 haad ### the device nodes we need are straight 361 1.1 haad if [ ${CHANGES_MADE} -eq 1 ] 362 1.1 haad then 363 1.1 haad "$LVM" vgscan ${LVM_OPTS} --mknodes 364 1.1 haad fi 365 1.1 haad 366 1.1 haad exit 0 367