6
# cabeca (at) ist (dot) utl (dot) pt
8
# Inspiration to write this script came from various sources
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/
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
20
# It needs lvm2 tools, busybox, pivot_root, MAKEDEV
22
# It has been tested on Debian sid (unstable) only
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
33
# Copyright Miguel Cabeca, Jeffrey Layton, 2004
35
# This program is free software; you can redistribute it and/or modify
36
# it under the terms of the GNU General Public License as published by
37
# the Free Software Foundation; either version 2 of the License, or
38
# (at your option) any later version.
40
# This program is distributed in the hope that it will be useful,
41
# but WITHOUT ANY WARRANTY; without even the implied warranty of
42
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43
# GNU General Public License for more details.
45
# You should have received a copy of the GNU General Public License
46
# along with this program; if not, write to the Free Software
47
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
49
# $Id: lvm2create_initrd,v 1.1 2004/06/07 16:20:05 agk Exp $
55
BINFILES=${BINFILES:-"/lib/lvm-200/lvm /bin/bash /bin/busybox /sbin/pivot_root"}
56
BASICDEVICES=${BASICDEVICES:-"std consoleonly fd"}
57
BLOCKDEVICES=${BLOCKDEVICES:-"md hda hdb hdc hdd sda sdb sdc sdd"}
58
MAKEDEV=${MAKEDEV:-"debian"}
60
# Uncomment this if you want to disable automatic size detection
63
PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH
66
echo "Create an initial ramdisk image for LVM2 root filesystem"
67
echo "$cmd: [-h] [-v] [-c lvm.conf] [-m modulelist] [-e extrafiles] -r [raiddevs] [-R mdadm.conf] [-M style] [kernel version]"
68
echo " -h|--help print this usage message"
69
echo " -v|--verbose verbose progress messages"
70
echo " -c|--lvmconf path to lvm.conf (/etc/lvm/lvm.conf)"
71
echo " -m|--modules modules to copy to initrd image"
72
echo " -e|--extra extra files to add to initrd"
73
echo " -r|--raid raid devices to start in initrd"
74
echo " -R|--raidconf location of mdadm.conf file to include"
75
echo " -M|--makedev set MAKEDEV type (debian or redhat)"
79
[ "$VERBOSE" ] && echo "`echo $cmd | tr '[a-z0-9/_]' ' '` -- $1" || true
83
[ "`mount | grep $DEVRAM`" ] && verbose "unmounting $DEVRAM" && umount $DEVRAM
84
[ -f $DEVRAM ] && verbose "removing $DEVRAM" && rm $DEVRAM
85
[ -d $TMPMNT ] && verbose "removing $TMPMNT" && rmdir $TMPMNT
86
verbose "exit with code $1"
91
verbose 'Caught interrupt'
97
cat << 'INIT' > $TMPMNT/sbin/init
100
# include in the path some dirs from the real root filesystem
101
# for chroot, blockdev
102
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/lib/lvm-200:/initrd/bin:/initrd/sbin"
107
/bin/echo "*** Entering LVM2 rescue shell. Exit shell to continue booting. ***"
112
echo "$PRE Remounting / read/write"
113
mount -t ext2 -o remount,rw /dev/ram0 /
116
# We need /proc for device mapper
117
echo "$PRE Mounting /proc"
118
mount -t proc none /proc
120
# plug in modules listed in /etc/modules
121
if [ -f /etc/modules ]; then
122
echo -n "$PRE plugging in kernel modules:"
124
while read module; do
131
# start raid devices if raid_autostart file exists
132
if [ -f /etc/raid_autostart ]; then
133
if [ ! -f /etc/mdadm/mdadm.conf ]; then
134
mdoptions='--super-minor=dev'
136
cat /etc/raid_autostart|
138
echo "Starting RAID device $dev"
139
/sbin/mdadm --assemble $dev $mdoptions
143
# Create the /dev/mapper/control device for the ioctl
144
# interface using the major and minor numbers that have been allocated
147
echo -n "$PRE Finding device mapper major and minor numbers "
149
MAJOR=$(sed -n 's/^ *\([0-9]\+\) \+misc$/\1/p' /proc/devices)
150
MINOR=$(sed -n 's/^ *\([0-9]\+\) \+device-mapper$/\1/p' /proc/misc)
151
if test -n "$MAJOR" -a -n "$MINOR" ; then
152
mkdir -p -m 755 /dev/mapper
153
mknod -m 600 /dev/mapper/control c $MAJOR $MINOR
156
echo "($MAJOR,$MINOR)"
158
# Device-Mapper dynamically allocates all device numbers. This means it is possible
159
# that the root volume specified to LILO or Grub may have a different number when the
160
# initrd runs than when the system was last running. In order to make sure the
161
# correct volume is mounted as root, the init script must determine what the
162
# desired root volume name is by getting the LVM2 root volume name from the kernel command line. In order for
163
# this to work correctly, "lvm2root=/dev/Volume_Group_Name/Root_Volume_Name" needs to be passed
164
# to the kernel command line (where Root_Volume_Name is replaced by your actual
165
# root volume's name.
166
for arg in `cat /proc/cmdline`; do
167
echo $arg | grep '^lvm2root=' > /dev/null
168
if [ $? -eq 0 ]; then
169
rootvol=${arg#lvm2root=}
174
echo "$PRE Activating LVM2 volumes"
177
# run a shell if we're passed lvm2rescue on commandline
178
grep lvm2rescue /proc/cmdline 1>/dev/null 2>&1
179
if [ $? -eq 0 ]; then
180
lvm vgchange --ignorelockingfailure -P -a y
183
lvm vgchange --ignorelockingfailure -a y
186
echo "$PRE Mounting root filesystem $rootvol ro"
188
if ! mount -t auto -o ro $rootvol /rootvol; then
193
echo "$PRE Umounting /proc"
196
echo "$PRE Changing roots"
198
if ! pivot_root . initrd ; then
203
echo "$PRE Proceeding with boot..."
205
exec chroot . /bin/sh -c "umount /initrd; blockdev --flushbufs /dev/ram0 ; exec /sbin/init $*" < dev/console > dev/console 2>&1
208
chmod 555 $TMPMNT/sbin/init
211
# create lvm.conf file from dumpconfig. Just use filter options
213
echo 'devices {' > $TMPMNT/etc/lvm/lvm.conf
214
lvm dumpconfig | grep 'filter=' >> $TMPMNT/etc/lvm/lvm.conf
215
echo '}' >> $TMPMNT/etc/lvm/lvm.conf
226
while [ $# -gt 0 ]; do
228
-h|--help) usage; exit 0;;
229
-v|--verbose) VERBOSE="y";;
230
-c|--lvmconf) LVMCONF=$2; shift;;
231
-m|--modules) MODULES=$2; shift;;
232
-e|--extra) EXTRAFILES=$2; shift;;
233
-r|--raid) RAID=$2; shift;;
234
-R|--raidconf) RAIDCONF=$2; shift;;
235
-M|--makedev) MAKEDEV=$2; shift;;
236
[2-9].[0-9]*.[0-9]*) VERSION=$1;;
237
*) echo "$cmd -- invalid option '$1'"; usage; exit 0;;
242
INITRD=${INITRD:-"/boot/initrd-lvm2-$VERSION.gz"}
244
echo "$cmd -- make LVM initial ram disk $INITRD"
247
if [ -n "$RAID" ]; then
248
BINFILES="$BINFILES /sbin/mdadm"
249
RAIDCONF=${RAIDCONF:-"/etc/mdadm/mdadm.conf"}
250
if [ -r $RAIDCONF ]; then
251
EXTRAFILES="$EXTRAFILES $RAIDCONF"
253
echo "$cmd -- WARNING: No $RAIDCONF! Your RAID device minor numbers must match their superblock values!"
257
# add modprobe if we declared any modules
258
if [ -n "$MODULES" ]; then
259
BINFILES="$BINFILES /sbin/modprobe /sbin/insmod /sbin/rmmod"
262
for a in $BINFILES $EXTRAFILES; do
263
if [ ! -r "$a" ] ; then
264
echo "$cmd -- ERROR: you need $a"
269
# Figure out which shared libraries we actually need in our initrd
270
echo "$cmd -- finding required shared libraries"
271
verbose "BINFILES: `echo $BINFILES`"
272
LIBFILES=`ldd $BINFILES 2>/dev/null | awk '{if (/=>/) { print $3 }}' | sort -u`
273
if [ $? -ne 0 ]; then
274
echo "$cmd -- ERROR figuring out needed shared libraries"
278
verbose "Shared libraries needed: `echo $LIBFILES`"
280
INITRDFILES="$BINFILES $LIBFILES $MODULES $EXTRAFILES"
282
# tack on stuff for modules if we declared any and the files exist
283
if [ -n "$MODULES" ]; then
284
if [ -f "/etc/modprobe.conf" ]; then
285
INITRDFILES="$INITRDFILES /etc/modprobe.conf"
287
if [ -f "/lib/modules/modprobe.conf" ]; then
288
INITRDFILES="$INITRDFILES /lib/modules/modprobe.conf"
292
# Calculate the the size of the ramdisk image.
293
# Don't forget that inodes take up space too, as does the filesystem metadata.
294
echo "$cmd -- calculating initrd filesystem parameters"
295
if [ -z "$INITRDSIZE" ]; then
296
echo "$cmd -- calculating loopback file size"
297
verbose "finding size"
298
INITRDSIZE="`du -Lck $INITRDFILES | tail -1 | cut -f 1`"
299
verbose "minimum: $INITRDSIZE kB for files + inodes + filesystem metadata"
300
INITRDSIZE=`expr $INITRDSIZE + 512` # enough for ext2 fs + a bit
303
echo "$cmd -- making loopback file ($INITRDSIZE kB)"
304
verbose "using $DEVRAM as a temporary loopback file"
305
dd if=/dev/zero of=$DEVRAM count=$INITRDSIZE bs=1024 > /dev/null 2>&1
306
if [ $? -ne 0 ]; then
307
echo "$cmd -- ERROR creating loopback file"
311
echo "$cmd -- making ram disk filesystem"
312
verbose "mke2fs -F -m0 -L LVM-$VERSION $DEVRAM $INITRDSIZE"
313
[ "$VERBOSE" ] && OPT_Q="" || OPT_Q="-q"
314
mke2fs $OPT_Q -F -m0 -L LVM-$VERSION $DEVRAM $INITRDSIZE
315
if [ $? -ne 0 ]; then
316
echo "$cmd -- ERROR making ram disk filesystem"
317
echo "$cmd -- ERROR you need to use mke2fs >= 1.14 or increase INITRDSIZE"
321
verbose "creating mountpoint $TMPMNT"
323
if [ $? -ne 0 ]; then
324
echo "$cmd -- ERROR making $TMPMNT"
328
echo "$cmd -- mounting ram disk filesystem"
329
verbose "mount -o loop $DEVRAM $TMPMNT"
330
mount -oloop $DEVRAM $TMPMNT
331
if [ $? -ne 0 ]; then
332
echo "$cmd -- ERROR mounting $DEVRAM on $TMPMNT"
336
verbose "creating basic set of directories in $TMPMNT"
337
(cd $TMPMNT; mkdir bin dev etc lib proc sbin var)
338
if [ $? -ne 0 ]; then
339
echo "$cmd -- ERROR creating directories in $TMPMNT"
343
# Add some /dev files. We have to handle different types of MAKEDEV invocations
344
# here, so this is rather messy.
346
echo "$cmd -- adding required /dev files"
347
verbose "BASICDEVICES: `echo $BASICDEVICES`"
348
verbose "BLOCKDEVICES: `echo $BLOCKDEVICES`"
349
[ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q=""
352
(cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES)
356
(cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q -d $TMPMNT/dev -m 2)
360
echo "$cmd -- ERROR: $MAKEDEV is not a known MAKEDEV style."
366
if [ $RETCODE -ne 0 ]; then
367
echo "$cmd -- ERROR adding /dev files"
372
# copy necessary files to ram disk
373
echo "$cmd -- copying initrd files to ram disk"
374
[ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q="--quiet"
375
verbose "find \$INITRDFILES | cpio -pdmL $OPT_Q $TMPMNT"
376
find $INITRDFILES | cpio -pdmL $OPT_Q $TMPMNT
377
if [ $? -ne 0 ]; then
378
echo "$cmd -- ERROR cpio to ram disk"
383
echo "$cmd -- creating symlinks to busybox"
385
[ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q=""
386
BUSYBOXSYMLINKS=`busybox 2>&1| awk '/^Currently defined functions:$/ {i++;next} i'|tr ',\t\n' ' '`
387
for link in ${BUSYBOXSYMLINKS//@(linuxrc|init|busybox)}; do
388
ln -s $OPT_Q busybox $TMPMNT/bin/$link;
392
echo "$cmd -- creating new $TMPMNT/sbin/init"
394
if [ $? -ne 0 ]; then
395
echo "$cmd -- ERROR creating init"
400
# copy LVMCONF into place or create a stripped down one from lvm dumpconfig
401
mkdir -p $TMPMNT/etc/lvm
402
if [ -n "$LVMCONF" ]; then
403
echo "$cmd -- copying $LVMCONF to $TMPMNT/etc/lvm/lvm.conf"
404
if [ -f "$LVMCONF" ]; then
405
cp $LVMCONF $TMPMNT/etc/lvm/lvm.conf
407
echo "$cmd -- ERROR: $LVMCONF does not exist!"
412
echo "$cmd -- creating new $TMPMNT/etc/lvm/lvm.conf"
416
if [ -n "$RAID" ]; then
417
RAIDLIST="$TMPMNT/etc/raid_autostart"
418
echo "$cmd -- creating $RAIDLIST file."
419
for device in $RAID; do
420
echo $device >> $RAIDLIST
424
# create modules.dep and /etc/modules files if needed
425
if [ -n "$MODULES" ]; then
426
echo "$cmd -- creating $MODDIR/modules.dep file and $TMPMNT/etc/modules"
427
depmod -b $TMPMNT $VERSION
428
for module in $MODULES; do
429
basename $module | sed 's/\.k\{0,1\}o$//' >> $TMPMNT/etc/modules
433
verbose "removing $TMPMNT/lost+found"
434
rmdir $TMPMNT/lost+found
436
echo "$cmd -- ummounting ram disk"
438
if [ $? -ne 0 ]; then
439
echo "$cmd -- ERROR umounting $DEVRAM"
443
echo "$cmd -- creating compressed initrd $INITRD"
444
verbose "dd if=$DEVRAM bs=1k count=$INITRDSIZE | gzip -9"
445
dd if=$DEVRAM bs=1k count=$INITRDSIZE 2>/dev/null | gzip -9 > $INITRD
446
if [ $? -ne 0 ]; then
447
echo "$cmd -- ERROR creating $INITRD"
453
--------------------------------------------------------
454
Your initrd is ready in $INITRD
456
Don't forget to set root=/dev/ram0 in kernel parameters
457
Don't forget to set lvm2root=/dev/VG/LV in kernel parameters, where LV is your root volume
458
If you use lilo try adding/modifying an entry similar to this one in lilo.conf:
460
image=/boot/vmlinuz-lvm2-$VERSION
462
initrd=/boot/initrd-lvm2-$VERSION.gz
463
append="root=/dev/ram0 lvm2root=/dev/system/root <other parameters>"
465
If using grub try adding/modifying an entry similar to this one in menu.lst
468
kernel /boot/vmlinuz-lvm2-$VERSION root=/dev/ram0 lvm2root=/dev/system/root <other parameters>
469
initrd /boot/initrd-lvm2-$VERSION.gz
471
You can also pass lvm2rescue to the kernel to get a shell
472
--------------------------------------------------------