Tizen 2.1 base
[external/device-mapper.git] / scripts / vgimportclone.sh
1 #!/bin/bash
2
3 # Copyright (C) 2009 Chris Procter All rights reserved.
4 # Copyright (C) 2009 Red Hat, Inc. All rights reserved.
5 #
6 # This file is part of LVM2.
7 #
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.
11 #
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
15 #
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)
18
19 # following external commands are used throughout the script
20 # echo and test are internal in bash at least
21 RM=rm
22 BASENAME=basename
23 MKTEMP=mktemp
24 AWK=awk
25 CUT=cut
26 TR=tr
27 READLINK=readlink
28 GREP=grep
29 GETOPT=getopt
30
31 # user may override lvm location by setting LVM_BINARY
32 LVM="${LVM_BINARY:-lvm}"
33
34 die() {
35     code=$1; shift
36     echo "Fatal: $@" 1>&2
37     exit $code
38 }
39
40 "$LVM" version >& /dev/null || die 2 "Could not run lvm binary '$LVM'"
41
42
43 function getvgname {
44 ### get a unique vg name
45 ###        $1 = list of exists VGs
46 ###        $2 = the name we want
47     VGLIST=$1
48     VG=$2
49     NEWVG=$3
50
51     BNAME="${NEWVG:-${VG}}"
52     NAME="${BNAME}"
53     I=0
54
55     while [[ "${VGLIST}" =~ "${NAME}" ]]
56     do
57         I=$(($I+1))
58         NAME="${BNAME}$I"
59     done
60     echo "${NAME}"
61 }
62
63
64 function checkvalue {
65 ### check return value and error if non zero
66     if [ $1 -ne 0 ]
67     then
68         die $1 "$2, error: $1"
69     fi
70 }
71
72
73 function usage {
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"
84     echo ""
85     exit 1
86 }
87
88
89 function cleanup {
90     #set to use old lvm.conf
91     LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR}
92
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."
95     else
96         "$RM" -rf -- "${TMP_LVM_SYSTEM_DIR}"
97     fi
98 }
99
100 SCRIPTNAME=`"$BASENAME" $0`
101
102
103 if [ "$UID" != "0" -a "$EUID" != "0" ]
104 then
105     die 3 "${SCRIPTNAME} must be run as root."
106 fi
107
108 LVM_OPTS=""
109 TEST_OPT=""
110 DISKS=""
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
114 CHANGES_MADE=0
115 IMPORT=0
116 DEBUG=""
117 VERBOSE=""
118 VERBOSE_COUNT=0
119 DEVNO=0
120
121 if [ -n "${LVM_SYSTEM_DIR}" ]; then
122     export ORIG_LVM_SYS_DIR="${LVM_SYSTEM_DIR}"
123 fi
124
125 trap  cleanup 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
126
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"
135
136 while true
137 do
138     case $1 in
139         -n|--basevgname)
140             NEWVG="$2"; shift; shift
141             ;;
142         -i|--import)
143             IMPORT=1; shift
144             ;;
145         -t|--test)
146             TEST_OPT="-t"
147             shift
148             ;;
149         --quiet)
150             LVM_OPTS="--quiet ${LVM_OPTS}"
151             shift
152             ;;
153         -v|--verbose)
154             let VERBOSE_COUNT=VERBOSE_COUNT+1
155             if [ -z "$VERBOSE" ]
156             then
157                 VERBOSE="-v"
158             else
159                 VERBOSE="${VERBOSE}v"
160             fi
161             shift
162             ;;
163         -d|--debug)
164             if [ -z "$DEBUG" ]
165             then
166                 DEBUG="-d"
167                 set -x
168             else
169                 DEBUG="${DEBUG}d"
170             fi
171             shift
172             ;;
173         --version)
174             "$LVM" version
175             shift
176             exit 0
177             ;;
178         -h|--help)
179             usage; shift
180             ;;
181         --)
182             shift; break
183             ;;
184         *)
185             usage
186             ;;
187     esac
188 done
189
190 # turn on DEBUG (special case associated with -v use)
191 if [ -z "$DEBUG" -a $VERBOSE_COUNT -gt 3 ]; then
192     DEBUG="-d"
193     set -x
194 fi
195
196 # setup LVM_OPTS
197 if [ -n "${DEBUG}" -o -n "${VERBOSE}" ]
198 then
199     LVM_OPTS="${LVM_OPTS} ${DEBUG} ${VERBOSE}"
200 fi
201
202 # process remaining arguments (which should be disks)
203 for ARG
204 do
205     if [ -b "$ARG" ]
206     then
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."
211
212         ln -s "$ARG" ${TMP_LVM_SYSTEM_DIR}/vgimport${DEVNO}
213         DISKS="${DISKS} ${TMP_LVM_SYSTEM_DIR}/vgimport${DEVNO}"
214         DEVNO=$((${DEVNO}+1))
215     else
216         die 3 "$ARG is not a block device."
217     fi
218 done
219
220 ### check we have suitable values for important variables
221 if [ -z "${DISKS}" ]
222 then
223     usage
224 fi
225
226 #####################################################################
227 ### Get the existing state so we can use it later
228 #####################################################################
229
230 OLDVGS=`"${LVM}" vgs ${LVM_OPTS} -o name --noheadings 2>/dev/null`
231 checkvalue $? "Current VG names could not be collected without errors"
232
233 #####################################################################
234 ### Prepare the temporary lvm environment
235 #####################################################################
236
237 for BLOCK in ${DISKS}
238 do
239     FILTER="\"a|^${BLOCK}$|\", ${FILTER}"
240 done
241 export FILTER="filter=[ ${FILTER} \"r|.*|\" ]"
242
243 LVMCONF=${TMP_LVM_SYSTEM_DIR}/lvm.conf
244
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}
253
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
257
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."
263
264 # check for either 'cache' or 'cache_dir' config values
265 "$GREP" -q '[[:space:]]*cache[[:space:]]*=' ${LVMCONF}
266 CACHE_RET=$?
267 "$GREP" -q '^[[:space:]]*cache_dir' ${LVMCONF}
268 CACHE_DIR_RET=$?
269 [ $CACHE_RET -eq 0 -o $CACHE_DIR_RET -eq 0 ] || \
270     die 7 "Temporary lvm.conf must contain 'cache' or 'cache_dir' config."
271
272 ### set to use new lvm.conf
273 export LVM_SYSTEM_DIR=${TMP_LVM_SYSTEM_DIR}
274
275
276 #####################################################################
277 ### Rename the VG(s) and change the VG and PV UUIDs.
278 #####################################################################
279
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"
282
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"
290
291 for VG in ${VGINFO}
292 do
293     VGNAME=`echo "${VG}" | "$CUT" -d: -f1`
294     EXPORTED=`echo "${VG}" | "$CUT" -d: -f2`
295     PVLIST=`echo "${VG}" | "$CUT" -d: -f3- | "$TR" , ' '`
296
297     if [ -z "${VGNAME}" ]
298     then
299         FOLLOWLIST=""
300         for DEV in $PVLIST; do
301             FOLLOW=`"$READLINK" $DEV`
302             FOLLOWLIST="$FOLLOW $FOLLOWLIST"
303         done
304         die 8 "Specified PV(s) ($FOLLOWLIST) don't belong to a VG."
305     fi
306
307     if [ -n "${EXPORTED}" ]
308     then
309         if [ ${IMPORT} -eq 1 ]
310         then
311             "$LVM" vgimport ${LVM_OPTS} ${TEST_OPT} "${VGNAME}"
312             checkvalue $? "Volume Group ${VGNAME} could not be imported"
313         else
314             echo "Volume Group ${VGNAME} exported, skipping."
315             continue
316         fi
317     fi
318
319     ### change the pv uuids
320     if [[ "${PVLIST}" =~ "unknown" ]]
321     then
322         echo "Volume Group ${VGNAME} has unknown PV(s), skipping."
323         echo "- Were all associated PV(s) supplied as arguments?"
324         continue
325     fi
326
327     for BLOCKDEV in ${PVLIST}
328     do
329         "$LVM" pvchange ${LVM_OPTS} ${TEST_OPT} --uuid ${BLOCKDEV} --config 'global{activation=0}'
330         checkvalue $? "Unable to change PV uuid for ${BLOCKDEV}"
331     done
332
333     NEWVGNAME=`getvgname "${OLDVGS}" "${VGNAME}" "${NEWVG}"`
334
335     "$LVM" vgchange ${LVM_OPTS} ${TEST_OPT} --uuid "${VGNAME}" --config 'global{activation=0}'
336     checkvalue $? "Unable to change VG uuid for ${VGNAME}"
337
338     ## if the name isn't going to get changed dont even try.
339     if [ "${VGNAME}" != "${NEWVGNAME}" ]
340     then
341         "$LVM" vgrename ${LVM_OPTS} ${TEST_OPT} "${VGNAME}" "${NEWVGNAME}"
342         checkvalue $? "Unable to rename ${VGNAME} to ${NEWVGNAME}"
343     fi
344
345     CHANGES_MADE=1
346 done
347
348 #####################################################################
349 ### Restore the old environment
350 #####################################################################
351 ### set to use old lvm.conf
352 if [ -z "${ORIG_LVM_SYS_DIR}" ]
353 then
354     unset LVM_SYSTEM_DIR
355 else
356     LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR}
357 fi
358
359 ### update the device cache and make sure all
360 ### the device nodes we need are straight
361 if [ ${CHANGES_MADE} -eq 1 ]
362 then
363     "$LVM" vgscan ${LVM_OPTS} --mknodes
364 fi
365
366 exit 0