Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / lvm2 / dist / scripts / lvm2create_initrd / lvm2create_initrd
1 #!/bin/bash
2 #
3 # lvm2create_initrd 
4 #
5 # Miguel Cabeca 
6 # cabeca (at) ist (dot) utl (dot) pt
7 #
8 # Inspiration to write this script came from various sources
9 #
10 # Original LVM lvmcreate_initrd: ftp://ftp.sistina.com/pub/LVM/1.0/
11 # Kernel initrd.txt: http://www.kernel.org/
12 # EVMS INSTALL.initrd & linuxrc: http://evms.sourceforge.net/
13 # Jeffrey Layton's lvm2create_initrd: http://poochiereds.net/svn/lvm2create_initrd/
14 # Christophe Saout's initrd & linuxrc: http://www.saout.de/misc/
15 #
16 # This script was only tested with kernel 2.6 with everything required to boot 
17 # the root filesystem built-in (not as modules). Ex: SCSI or IDE, RAID, device mapper
18 # It does not support devfs as it is deprecated in the 2.6 kernel series
19 #
20 # It needs lvm2 tools, busybox, pivot_root, MAKEDEV
21 #
22 # It has been tested on Debian sid (unstable) only
23 #
24 # Changelog
25 # 26/02/2004    Initial release -- Miguel Cabeca
26 # 27/02/2004    Removed the BUSYBOXSYMLINKS var. The links are now determined at runtime.
27 #               some changes in init script to call a shell if something goes wrong. -- Miguel Cabeca
28 # 19/04/2004    Several small changes. Pass args to init so single user mode works. Add some
29 #               PATH entries to /sbin/init shell script so chroot works without /usr mounted. Remove
30 #               mkdir /initrd so we don't cause problems if root filesystem is corrupted. -- Jeff Layton
31 # 15/05/2004    initial support for modules, create lvm.conf from lvm dumpconfig, other cleanups -- Jeff Layton
32 # 14/11/2006    Update handling of ldd output to handle hardcoded library links and virtual dll linux-gate.
33 #               Add support for Gentoo-style MAKEDEV. Remove hardcoded BINUTILS paths -- Douglas Mayle
34 #
35 # Copyright Miguel Cabeca, Jeffrey Layton, 2004
36 #
37 #    This program is free software; you can redistribute it and/or modify
38 #    it under the terms of the GNU General Public License as published by
39 #    the Free Software Foundation; either version 2 of the License, or
40 #    (at your option) any later version.
41 #
42 #    This program is distributed in the hope that it will be useful,
43 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
44 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
45 #    GNU General Public License for more details.
46 #
47 #    You should have received a copy of the GNU General Public License
48 #    along with this program; if not, write to the Free Software
49 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
50 #
51 # $Id: lvm2create_initrd,v 1.1.1.1 2008/12/22 00:18:58 haad Exp $
52
53 TMPMNT=/tmp/mnt.$$
54 DEVRAM=/tmp/initrd.$$
55
56 # set defaults
57 BINFILES=${BINFILES:-"`which lvm` `which bash` `which busybox` `which pivot_root`"}
58 BASICDEVICES=${BASICDEVICES:-"std consoleonly fd"}
59 BLOCKDEVICES=${BLOCKDEVICES:-"md hda hdb hdc hdd sda sdb sdc sdd"}
60 MAKEDEV=${MAKEDEV:-"debian"}
61
62 # Uncomment this if you want to disable automatic size detection
63 #INITRDSIZE=4096
64
65 PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH
66
67 usage () {
68         echo "Create an initial ramdisk image for LVM2 root filesystem"
69         echo "$cmd: [-h] [-v] [-c lvm.conf] [-m modulelist] [-e extrafiles] -r [raiddevs] [-R mdadm.conf] [-M style] [kernel version]"
70         echo "      -h|--help      print this usage message"
71         echo "      -v|--verbose   verbose progress messages"
72         echo "      -c|--lvmconf   path to lvm.conf (/etc/lvm/lvm.conf)"
73         echo "      -m|--modules   modules to copy to initrd image"
74         echo "      -e|--extra     extra files to add to initrd"
75         echo "      -r|--raid      raid devices to start in initrd"
76         echo "      -R|--raidconf  location of mdadm.conf file to include"
77         echo "      -M|--makedev   set MAKEDEV type (debian or redhat)"
78 }
79
80 verbose () {
81    [ "$VERBOSE" ] && echo "`echo $cmd | tr '[a-z0-9/_]' ' '` -- $1" || true
82 }
83
84 cleanup () {
85   [ "`mount | grep $DEVRAM`" ] && verbose "unmounting $DEVRAM" && umount $DEVRAM
86   [ -f $DEVRAM ] && verbose "removing $DEVRAM" && rm $DEVRAM
87   [ -d $TMPMNT ] && verbose "removing $TMPMNT" && rmdir $TMPMNT
88   verbose "exit with code $1"
89   exit $1
90 }
91
92 trap "
93   verbose 'Caught interrupt'
94   echo 'Bye bye...'
95   cleanup 1
96 " 1 2 3 15
97
98 create_init () {
99    cat << 'INIT' > $TMPMNT/sbin/init
100 #!/bin/bash
101
102 # include in the path some dirs from the real root filesystem
103 # for chroot, blockdev
104 PATH="/sbin:/bin:/usr/sbin:/usr/bin:/lib/lvm-200:/initrd/bin:/initrd/sbin"
105 PRE="initrd:"
106
107 do_shell(){
108     /bin/echo
109     /bin/echo "*** Entering LVM2 rescue shell. Exit shell to continue booting. ***"
110     /bin/echo
111     /bin/bash
112 }
113
114 echo "$PRE Remounting / read/write"
115 mount -t ext2 -o remount,rw /dev/ram0 /
116
117
118 # We need /proc for device mapper
119 echo "$PRE Mounting /proc"
120 mount -t proc none /proc
121
122 # plug in modules listed in /etc/modules
123 if [ -f /etc/modules ]; then
124     echo -n "$PRE plugging in kernel modules:"
125     cat /etc/modules |
126     while read module; do
127         echo -n " $module"
128         modprobe $module
129     done
130     echo '.'
131 fi
132
133 # start raid devices if raid_autostart file exists
134 if [ -f /etc/raid_autostart ]; then
135     if [ ! -f /etc/mdadm/mdadm.conf ]; then
136         mdoptions='--super-minor=dev'
137     fi
138     cat /etc/raid_autostart|
139     while read dev; do
140         echo "Starting RAID device $dev"
141         /sbin/mdadm --assemble $dev $mdoptions 
142     done
143 fi
144
145 # Create the /dev/mapper/control device for the ioctl
146 # interface using the major and minor numbers that have been allocated
147 # dynamically.
148
149 echo -n "$PRE Finding device mapper major and minor numbers "
150
151 MAJOR=$(sed -n 's/^ *\([0-9]\+\) \+misc$/\1/p' /proc/devices)
152 MINOR=$(sed -n 's/^ *\([0-9]\+\) \+device-mapper$/\1/p' /proc/misc)
153 if test -n "$MAJOR" -a -n "$MINOR" ; then
154         mkdir -p -m 755 /dev/mapper
155         mknod -m 600 /dev/mapper/control c $MAJOR $MINOR
156 fi
157
158 echo "($MAJOR,$MINOR)"
159
160 # Device-Mapper dynamically allocates all device numbers. This means it is possible 
161 # that the root volume specified to LILO or Grub may have a different number when the
162 # initrd runs than when the system was last running. In order to make sure the
163 # correct volume is mounted as root, the init script must determine what the
164 # desired root volume name is by getting the LVM2 root volume name from the kernel command line. In order for
165 # this to work correctly, "lvm2root=/dev/Volume_Group_Name/Root_Volume_Name" needs to be passed 
166 # to the kernel command line (where Root_Volume_Name is replaced by your actual
167 # root volume's name.
168 for arg in `cat /proc/cmdline`; do
169         echo $arg | grep '^lvm2root=' > /dev/null
170         if [ $? -eq 0 ]; then
171                 rootvol=${arg#lvm2root=}
172                 break
173         fi
174 done
175
176 echo "$PRE Activating LVM2 volumes"
177
178
179 # run a shell if we're passed lvm2rescue on commandline
180 grep lvm2rescue /proc/cmdline 1>/dev/null 2>&1
181 if [ $? -eq 0 ]; then
182     lvm vgchange --ignorelockingfailure -P -a y
183     do_shell
184 else
185     lvm vgchange --ignorelockingfailure -a y
186 fi
187
188 echo "$PRE Mounting root filesystem $rootvol ro"
189 mkdir /rootvol
190 if ! mount -t auto -o ro $rootvol /rootvol; then
191         echo "\t*FAILED*";
192         do_shell
193 fi
194
195 echo "$PRE Umounting /proc"
196 umount /proc
197
198 echo "$PRE Changing roots"
199 cd /rootvol
200 if ! pivot_root . initrd ; then
201         echo "\t*FAILED*"
202         do_shell
203 fi
204
205 echo "$PRE Proceeding with boot..."
206
207 exec chroot . /bin/sh -c "umount /initrd; blockdev --flushbufs /dev/ram0 ; exec /sbin/init $*" < dev/console > dev/console 2>&1
208
209 INIT
210    chmod 555 $TMPMNT/sbin/init
211 }
212
213 # create lvm.conf file from dumpconfig. Just use filter options
214 create_lvmconf () {
215     echo 'devices {' > $TMPMNT/etc/lvm/lvm.conf
216     lvm dumpconfig | grep 'filter=' >> $TMPMNT/etc/lvm/lvm.conf
217     echo '}' >> $TMPMNT/etc/lvm/lvm.conf
218 }
219
220 #
221 # Main
222 #
223
224 cmd=`basename $0`
225
226 VERSION=`uname -r`
227
228 while [ $# -gt 0 ]; do
229    case $1 in
230    -h|--help) usage; exit 0;;
231    -v|--verbose)  VERBOSE="y";;
232    -c|--lvmconf)  LVMCONF=$2; shift;;
233    -m|--modules)  MODULES=$2; shift;;
234    -e|--extra)    EXTRAFILES=$2; shift;;
235    -r|--raid)     RAID=$2; shift;;
236    -R|--raidconf) RAIDCONF=$2; shift;;
237    -M|--makedev)  MAKEDEV=$2; shift;;
238    [2-9].[0-9]*.[0-9]*) VERSION=$1;;
239    *) echo "$cmd -- invalid option '$1'"; usage; exit 0;;
240    esac
241    shift
242 done
243
244 INITRD=${INITRD:-"/boot/initrd-lvm2-$VERSION.gz"}
245
246 echo "$cmd -- make LVM initial ram disk $INITRD"
247 echo ""
248
249 if [ -n "$RAID" ]; then
250     BINFILES="$BINFILES /sbin/mdadm"
251     RAIDCONF=${RAIDCONF:-"/etc/mdadm/mdadm.conf"}
252     if [ -r $RAIDCONF ]; then
253         EXTRAFILES="$EXTRAFILES $RAIDCONF"
254     else
255         echo "$cmd -- WARNING: No $RAIDCONF! Your RAID device minor numbers must match their superblock values!"
256     fi
257 fi
258
259 # add modprobe if we declared any modules
260 if [ -n "$MODULES" ]; then
261     BINFILES="$BINFILES /sbin/modprobe /sbin/insmod /sbin/rmmod"
262 fi
263
264 for a in $BINFILES $EXTRAFILES; do
265     if [ ! -r "$a" ] ; then
266         echo "$cmd -- ERROR: you need $a"
267         exit 1;
268     fi;
269 done
270
271 # Figure out which shared libraries we actually need in our initrd
272 echo "$cmd -- finding required shared libraries"
273 verbose "BINFILES: `echo $BINFILES`"
274
275 # We need to strip certain lines from ldd output.  This is the full output of an example ldd:
276 #lvmhost~ # ldd /sbin/lvm /bin/bash
277 #/sbin/lvm:
278 #        not a dynamic executable
279 #/bin/bash:
280 #        linux-gate.so.1 =>  (0xbfffe000)
281 #        libncurses.so.5 => /lib/libncurses.so.5 (0xb7ee3000)
282 #        libdl.so.2 => /lib/libdl.so.2 (0xb7edf000)
283 #        libc.so.6 => /lib/libc.so.6 (0xb7dc1000)
284 #        /lib/ld-linux.so.2 (0xb7f28000)
285 #
286 # 1) Lines with a ":" contain the name of the original binary we're examining, and so are unnecessary.
287 #    We need to strip them because they contain "/", and can be confused with links with a hardcoded path.
288 # 2) The linux-gate library is a virtual dll that does not exist on disk, but is instead loaded automatically
289 #    into the process space, and can't be copied to the ramdisk
290 #
291 # After these lines have been stripped, we're interested in the lines remaining if they
292 # 1) Contain "=>" because they are pathless links, and the value following the token is the path on the disk
293 # 2) Contain "/" because it's a link with a hardcoded path, and so we're interested in the link itself.
294 LIBFILES=`ldd $BINFILES 2>/dev/null |grep -v -E \(linux-gate\|:\) | awk '{if (/=>/) { print $3 } else if (/\//) { print $1 }}' | sort -u`
295 if [ $? -ne 0 ]; then
296    echo "$cmd -- ERROR figuring out needed shared libraries"
297    exit 1
298 fi
299
300 verbose "Shared libraries needed: `echo $LIBFILES`"
301
302 INITRDFILES="$BINFILES $LIBFILES $MODULES $EXTRAFILES"
303
304 # tack on stuff for modules if we declared any and the files exist
305 if [ -n "$MODULES" ]; then
306     if [ -f "/etc/modprobe.conf" ]; then
307         INITRDFILES="$INITRDFILES /etc/modprobe.conf"
308     fi
309     if [ -f "/lib/modules/modprobe.conf" ]; then
310         INITRDFILES="$INITRDFILES /lib/modules/modprobe.conf"
311     fi
312 fi
313
314 # Calculate the the size of the ramdisk image.
315 # Don't forget that inodes take up space too, as does the filesystem metadata.
316 echo "$cmd -- calculating initrd filesystem parameters"
317 if [ -z "$INITRDSIZE" ]; then
318    echo "$cmd -- calculating loopback file size"
319    verbose "finding size"
320    INITRDSIZE="`du -Lck $INITRDFILES | tail -1 | cut -f 1`"
321    verbose "minimum: $INITRDSIZE kB for files + inodes + filesystem metadata"
322    INITRDSIZE=`expr $INITRDSIZE + 512`  # enough for ext2 fs + a bit
323 fi
324
325 echo "$cmd -- making loopback file ($INITRDSIZE kB)"
326 verbose "using $DEVRAM as a temporary loopback file"
327 dd if=/dev/zero of=$DEVRAM count=$INITRDSIZE bs=1024 > /dev/null 2>&1
328 if [ $? -ne 0 ]; then
329    echo "$cmd -- ERROR creating loopback file"
330    cleanup 1
331 fi
332
333 echo "$cmd -- making ram disk filesystem"
334 verbose "mke2fs -F -m0 -L LVM-$VERSION $DEVRAM $INITRDSIZE"
335 [ "$VERBOSE" ] && OPT_Q="" || OPT_Q="-q"
336 mke2fs $OPT_Q -F -m0 -L LVM-$VERSION $DEVRAM $INITRDSIZE
337 if [ $? -ne 0 ]; then
338    echo "$cmd -- ERROR making ram disk filesystem"
339    echo "$cmd -- ERROR you need to use mke2fs >= 1.14 or increase INITRDSIZE"
340    cleanup 1
341 fi
342
343 verbose "creating mountpoint $TMPMNT"
344 mkdir $TMPMNT
345 if [ $? -ne 0 ]; then
346    echo "$cmd -- ERROR making $TMPMNT"
347    cleanup 1
348 fi
349
350 echo "$cmd -- mounting ram disk filesystem"
351 verbose "mount -o loop $DEVRAM $TMPMNT"
352 mount -oloop $DEVRAM $TMPMNT
353 if [ $? -ne 0 ]; then
354    echo "$cmd -- ERROR mounting $DEVRAM on $TMPMNT"
355    cleanup 1
356 fi
357
358 verbose "creating basic set of directories in $TMPMNT"
359 (cd $TMPMNT; mkdir bin dev etc lib proc sbin var)
360 if [ $? -ne 0 ]; then
361    echo "$cmd -- ERROR creating directories in $TMPMNT"
362    cleanup 1
363 fi
364
365 # Add some /dev files. We have to handle different types of MAKEDEV invocations
366 # here, so this is rather messy.
367 RETCODE=0
368 echo "$cmd -- adding required /dev files"
369 verbose "BASICDEVICES: `echo $BASICDEVICES`"
370 verbose "BLOCKDEVICES: `echo $BLOCKDEVICES`"
371 [ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q=""
372 case "$MAKEDEV" in 
373 debian)
374     (cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES)
375     RETCODE=$?
376     ;;
377 redhat)
378     (cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q -d $TMPMNT/dev -m 2)
379     RETCODE=$?
380     ;;
381 gentoo)
382     (cd $TMPMNT/dev; /usr/sbin/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES)
383     RETCODE=$?
384     ;;
385 *)
386     echo "$cmd -- ERROR: $MAKEDEV is not a known MAKEDEV style."
387     RETCODE=1
388     ;;
389 esac
390
391
392 if [ $RETCODE -ne 0 ]; then
393    echo "$cmd -- ERROR adding /dev files"
394    cleanup 1
395 fi
396
397
398 # copy necessary files to ram disk
399 echo "$cmd -- copying initrd files to ram disk"
400 [ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q="--quiet"
401 verbose "find \$INITRDFILES | cpio -pdmL $OPT_Q $TMPMNT"
402 find $INITRDFILES | cpio -pdmL $OPT_Q $TMPMNT
403 if [ $? -ne 0 ]; then
404    echo "$cmd -- ERROR cpio to ram disk"
405    cleanup 1
406 fi
407
408
409 echo "$cmd -- creating symlinks to busybox"
410 shopt -s extglob
411 [ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q=""
412 BUSYBOXSYMLINKS=`busybox 2>&1| awk '/^Currently defined functions:$/ {i++;next} i'|tr ',\t\n' ' '`
413 for link in ${BUSYBOXSYMLINKS//@(linuxrc|init|busybox)}; do 
414         ln -s $OPT_Q busybox $TMPMNT/bin/$link;
415 done
416 shopt -u extglob
417
418 echo "$cmd -- creating new $TMPMNT/sbin/init"
419 create_init
420 if [ $? -ne 0 ]; then
421    echo "$cmd -- ERROR creating init"
422    cleanup
423    exit 1
424 fi
425
426 # copy LVMCONF into place or create a stripped down one from lvm dumpconfig
427 mkdir -p $TMPMNT/etc/lvm
428 if [ -n "$LVMCONF" ]; then
429     echo "$cmd -- copying $LVMCONF to $TMPMNT/etc/lvm/lvm.conf"
430     if [ -f "$LVMCONF" ]; then
431         cp $LVMCONF $TMPMNT/etc/lvm/lvm.conf
432     else
433         echo "$cmd -- ERROR: $LVMCONF does not exist!"
434         cleanup
435         exit 1
436     fi
437 else
438     echo "$cmd -- creating new $TMPMNT/etc/lvm/lvm.conf"
439     create_lvmconf
440 fi
441
442 if [ -n "$RAID" ]; then
443     RAIDLIST="$TMPMNT/etc/raid_autostart"
444     echo "$cmd -- creating $RAIDLIST file."
445     for device in $RAID; do
446         echo $device >> $RAIDLIST
447     done
448 fi
449
450 # create modules.dep and /etc/modules files if needed
451 if [ -n "$MODULES" ]; then
452     echo "$cmd -- creating $MODDIR/modules.dep file and $TMPMNT/etc/modules"
453     depmod -b $TMPMNT $VERSION
454     for module in $MODULES; do
455         basename $module | sed 's/\.k\{0,1\}o$//' >> $TMPMNT/etc/modules
456     done
457 fi
458
459 verbose "removing $TMPMNT/lost+found"
460 rmdir $TMPMNT/lost+found
461
462 echo "$cmd -- ummounting ram disk"
463 umount $DEVRAM
464 if [ $? -ne 0 ]; then
465    echo "$cmd -- ERROR umounting $DEVRAM"
466    cleanup 1
467 fi
468
469 echo "$cmd -- creating compressed initrd $INITRD"
470 verbose "dd if=$DEVRAM bs=1k count=$INITRDSIZE | gzip -9"
471 dd if=$DEVRAM bs=1k count=$INITRDSIZE 2>/dev/null | gzip -9 > $INITRD
472 if [ $? -ne 0 ]; then
473    echo "$cmd -- ERROR creating $INITRD"
474    cleanup 1
475 fi
476
477
478 cat << FINALTXT
479 --------------------------------------------------------
480 Your initrd is ready in $INITRD
481
482 Don't forget to set root=/dev/ram0 in kernel parameters
483 Don't forget to set lvm2root=/dev/VG/LV in kernel parameters, where LV is your root volume
484 If you use lilo try adding/modifying an entry similar to this one in lilo.conf:
485
486 image=/boot/vmlinuz-lvm2-$VERSION
487         label="ramdisk_LVM"
488         initrd=/boot/initrd-lvm2-$VERSION.gz
489         append="root=/dev/ram0 lvm2root=/dev/system/root <other parameters>"
490
491 If using grub try adding/modifying an entry similar to this one in menu.lst
492
493 title ramdisk LVM
494         kernel /boot/vmlinuz-lvm2-$VERSION root=/dev/ram0 lvm2root=/dev/system/root <other parameters>
495         initrd /boot/initrd-lvm2-$VERSION.gz
496
497 You can also pass lvm2rescue to the kernel to get a shell
498 --------------------------------------------------------
499 FINALTXT
500
501 cleanup 0
502