]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/nash/mkinitrd
2a36352de167db0c6ac06d76e15071d4cc73c989
[people/pmueller/ipfire-2.x.git] / src / nash / mkinitrd
1 #!/bin/bash
2
3 # mkinitrd
4 #
5 # Written by Erik Troan <ewt@redhat.com>
6 #
7 # Contributors:
8 # Elliot Lee <sopwith@cuc.edu>
9 # Miguel de Icaza <miguel@nuclecu.unam.mx>
10 # Christian 'Dr. Disk' Hechelmann <drdisk@ds9.au.s.shuttle.de>
11 # Michael K. Johnson <johnsonm@redhat.com>
12 # Pierre Habraken <Pierre.Habraken@ujf-grenoble.fr>
13 # Jakub Jelinek <jakub@redhat.com>
14 # Carlo Arenas Belon (carenas@chasqui.lared.net.pe>
15 # Keith Owens <kaos@ocs.com.au>
16 # Bernhard Rosenkraenzer <bero@redhat.com>
17 # Matt Wilson <msw@redhat.com>
18 # Trond Eivind Glomsrød <teg@redhat.com>
19 # Jeremy Katz <katzj@redhat.com>
20 # Preston Brown <pbrown@redhat.com>
21 # Bill Nottingham <notting@redhat.com>
22 # Guillaume Cottenceau <gc@mandrakesoft.com>
23
24
25 PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
26 export PATH
27
28 VERSION=3.5.14
29
30 compress=1
31 target=""
32 kernel=""
33 force=""
34 verbose=""
35 MODULES=""
36 img_vers=""
37 builtins=""
38 pivot=1
39 modulefile=/etc/modules.conf
40 rc=0
41
42 IMAGESIZE=5120
43 PRESCSIMODS="scsi_mod sd_mod unknown"
44 fstab="/etc/fstab"
45
46 usage () {
47 echo "usage: `basename $0` [--version] [-v] [-f] [--preload <module>]" >&2
48 echo " [--omit-scsi-modules] [--omit-raid-modules] [--omit-lvm-modules]" >&2
49 echo " [--with=<module>] [--image-version] [--fstab=<fstab>] [--nocompress]" >&2
50 echo " [--builtin=<module>] [--nopivot] <initrd-image> <kernel-version>" >&2
51 echo "" >&2
52 echo " (ex: `basename $0` /boot/initrd-2.2.5-15.img 2.2.5-15)" >&2
53 exit 1
54 }
55
56 moduledep() {
57 if [ ! -f "/lib/modules/$kernel/modules.dep" ]; then
58 echo "No dep file found for kernel $kernel" >&2
59 exit 1
60 fi
61
62 [ -n "$verbose" ] && echo -n "Looking for deps of module $1"
63 deps=$(gawk 'BEGIN { searched=ARGV[2]; ARGV[2]=""; rc=1 } \
64 function modname(filename) { match(filename, /\/([^\/]+)\.k?o/, ret); return ret[1] } \
65 function show() { if (orig == searched) { print dep; orig=""; rc=0; exit } } \
66 /^\/lib/ { show(); \
67 orig=modname($1); \
68 if ($2) { dep=modname($2) } else { dep="" } } \
69 /^ / { dep=sprintf("%s %s", dep, modname($1)); } \
70 END { show(); exit(rc) }' /lib/modules/$kernel/modules.dep $1)
71 [ -n "$verbose" ] && echo -e "\t$deps"
72 }
73
74 findmodule() {
75 skiperrors=""
76
77 if [ $1 == "--skiperrors" ]; then
78 skiperrors=--skiperrors
79 shift
80 fi
81
82 local modName=$1
83
84 if [ "$modName" = "off" -o "$modName" = "null" ]; then
85 return
86 fi
87
88 if [ $(echo $modName | cut -b1) = "-" ]; then
89 skiperrors=--skiperrors
90 modName=$(echo $modName | cut -b2-)
91 fi
92
93 if echo $builtins | grep -E -q '(^| )'$modName'( |$)' ; then
94 [ -n "$verbose" ] && echo "module $modName assumed to be built in"
95 set +x
96 return
97 fi
98
99 # special cases
100 if [ "$modName" = "i2o_block" ]; then
101 findmodule i2o_core
102 findmodule i2o_pci
103 modName="i2o_block"
104 elif [ "$modName" = "ppa" ]; then
105 findmodule parport
106 findmodule parport_pc
107 modName="ppa"
108 elif [ "$modName" = "sbp2" ]; then
109 findmodule ieee1394
110 findmodule ohci1394
111 modName="sbp2"
112 else
113 moduledep $modName
114 for i in $deps; do
115 findmodule $i
116 done
117 fi
118
119 for modExt in o.gz o ko ; do
120 if [ -d /lib/modules/$kernel/updates ]; then
121 fmPath=`(cd /lib/modules/$kernel/updates; echo find . -name $modName.$modExt -type f | /sbin/nash --quiet) | gawk {'print $1; exit;'}`
122 fi
123
124 if [ -f /lib/modules/$kernel/updates/$fmPath ]; then
125 fmPath=updates/$fmPath
126 break
127 fi
128
129 fmPath=`(cd /lib/modules/$kernel; echo find . -name $modName.$modExt -type f | /sbin/nash --quiet) | gawk {'print $1; exit;'}`
130 if [ -f /lib/modules/$kernel/$fmPath ]; then
131 break
132 fi
133 done
134
135 if [ ! -f /lib/modules/$kernel/$fmPath ]; then
136 if [ -n "$skiperrors" ]; then
137 return
138 fi
139
140 # ignore the absence of the scsi modules
141 for n in $PRESCSIMODS; do
142 if [ "$n" = "$modName" ]; then
143 return;
144 fi
145 done;
146
147 echo "No module $modName found for kernel $kernel, aborting." >&2
148 exit 1
149 fi
150
151 # only need to add each module once
152 if ! echo $MODULES | grep -q "$fmPath" 2>/dev/null ; then
153 MODULES="$MODULES $fmPath"
154 fi
155 }
156
157 inst() {
158 if [ "$#" != "2" ];then
159 echo "usage: inst <file> <destination>"
160 return
161 fi
162 [ -n "$verbose" ] && echo "$1 -> $2"
163 cp $1 $2
164 }
165
166 while [ $# -gt 0 ]; do
167 case $1 in
168 --fstab*)
169 if echo $1 | grep -q '=' ; then
170 fstab=`echo $1 | sed 's/^--fstab=//'`
171 else
172 fstab=$2
173 shift
174 fi
175 ;;
176
177 --with-usb)
178 withusb=yes
179 ;;
180
181 --with*)
182 if echo $1 | grep -q '=' ; then
183 modname=`echo $1 | sed 's/^--with=//'`
184 else
185 modname=$2
186 shift
187 fi
188
189 basicmodules="$basicmodules $modname"
190 ;;
191
192 --builtin*)
193 if echo $1 | grep -q '=' ; then
194 modname=`echo $1 | sed 's/^--builtin=//'`
195 else
196 modname=$2
197 shift
198 fi
199 builtins="$builtins $modname"
200 ;;
201
202 --version)
203 echo "mkinitrd: version $VERSION"
204 exit 0
205 ;;
206
207 -v)
208 verbose=-v
209 ;;
210
211 --nocompress)
212 compress=""
213 ;;
214
215 --nopivot)
216 pivot=""
217 ;;
218
219 --ifneeded)
220 # legacy
221 ;;
222
223 -f)
224 force=1
225 ;;
226 --preload*)
227 if echo $1 | grep -q '=' ; then
228 modname=`echo $1 | sed 's/^--preload=//'`
229 else
230 modname=$2
231 shift
232 fi
233 PREMODS="$PREMODS $modname"
234 ;;
235 --omit-scsi-modules)
236 PRESCSIMODS=""
237 noscsi=1;
238 ;;
239 --omit-raid-modules)
240 noraid=1;
241 ;;
242 --omit-lvm-modules)
243 nolvm=1
244 ;;
245 --image-version)
246 img_vers=yes
247 ;;
248 *)
249 if [ -z "$target" ]; then
250 target=$1
251 elif [ -z "$kernel" ]; then
252 kernel=$1
253 else
254 usage
255 fi
256 ;;
257 esac
258
259 shift
260 done
261
262 if [ -z "$target" -o -z "$kernel" ]; then
263 usage
264 fi
265
266 if [ -n "$img_vers" ]; then
267 target="$target-$kernel"
268 fi
269
270 if [ -z "$force" -a -f $target ]; then
271 echo "$target already exists." >&2
272 exit 1
273 fi
274
275 if [ ! -d /lib/modules/$kernel ]; then
276 echo "/lib/modules/$kernel is not a directory." >&2
277 exit 1
278 fi
279
280 if [ $UID != 0 ]; then
281 echo "mkinitrd must be run as root"
282 exit 1
283 fi
284
285 # find a temporary directory which doesn't use tmpfs
286 TMPDIR=""
287 for t in /tmp /var/tmp /root ${PWD}; do
288 if [ ! -d $t ]; then continue; fi
289 if ! echo access -w $t | /sbin/nash --quiet; then continue; fi
290
291 fs=$(df -T $t 2>/dev/null | gawk '{line=$1;} END {printf $2;}')
292 if [ "$fs" != "tmpfs" ]; then
293 TMPDIR=$t
294 break
295 fi
296 done
297
298 if [ -z "$TMPDIR" ]; then
299 echo "no temporary directory could be found" >&2
300 exit 1
301 fi
302
303 if [ $TMPDIR = "/root" -o $TMPDIR = "${PWD}" ]; then
304 echo "WARNING: using $TMPDIR for temporary files" >&2
305 fi
306
307 for n in $PREMODS; do
308 findmodule $n
309 done
310
311 needusb=""
312 if [ -n "$withusb" ]; then
313 # If / or /boot is on a USB device include the driver. With root by
314 # label we could still get some odd behaviors
315 for fs in / /boot ; do
316 esc=$(echo $fs | sed 's,/,\\/,g')
317 dev=$(mount | gawk "/ on ${esc} / { print \$1 }" | sed 's/[0-9]*$//' | cut -d/ -f3)
318 if [ "$(echo $dev | cut -c1-2)" = sd ]; then
319 if [ `which kudzu 2>/dev/null` ]; then
320 host=$(kudzu --probe -b scsi |
321 gawk '/^device: '${dev}'/,/^host:/ { if (/^host/) { print $2; exit; } }')
322 if [ -d /proc/scsi/usb-storage-${host} ]; then
323 needusb=1
324 fi
325 fi
326 fi
327 done
328 fi
329
330 if [ -n "$needusb" ]; then
331 drivers=$(gawk '/^alias usb-controller[0-9]* / { print $3}' < /etc/modules.conf)
332 if [ -n "$drivers" ]; then
333 for driver in $drivers; do
334 findmodule $driver
335 done
336 findmodule scsi_mod
337 findmodule sd_mod
338 findmodule usb-storage
339 fi
340 fi
341
342 if [ -z "$noscsi" ]; then
343 if [ ! -f $modulefile ]; then
344 modulefile=/etc/conf.modules
345 fi
346
347 if [ -f $modulefile ]; then
348 scsimodules=`grep "alias[[:space:]]scsi_hostadapter" $modulefile | grep -v '^[ ]*#' | LC_ALL=C sort -u | gawk '{ print $3 }'`
349
350 if [ -n "$scsimodules" ]; then
351 for n in $PRESCSIMODS; do
352 findmodule $n
353 done
354
355 for n in $scsimodules; do
356 # for now allow scsi modules to come from anywhere. There are some
357 # RAID controllers with drivers in block/
358 findmodule $n
359 done
360 fi
361 fi
362 fi
363
364 # If we have ide devices and module ide, do the right thing
365 ide=/proc/ide/ide*
366 if [ -n "$ide" ]; then
367 findmodule -ide-disk
368 fi
369
370 # If we use LVM, include lvm-mod
371 if [ -z "$nolvm" ]; then
372 if [ -f /proc/lvm/global ]; then
373 if grep -q '^VG:' /proc/lvm/global ; then
374 findmodule -lvm-mod
375 fi
376 fi
377 fi
378
379 # If we have dasd devices, include the necessary modules (S/390)
380 if [ -d /proc/dasd ]; then
381 findmodule -dasd_mod
382 findmodule -dasd_eckd_mod
383 findmodule -dasd_fba_mod
384 fi
385
386 if [ -z "$noraid" -a -f /proc/mdstat ]; then
387 # load appropriate raid devices if necessary -- we'll load whatever
388 # /proc/mdstat suggests
389
390 # note that the gawk below contains a space and a tab
391 for level in $(gawk '/^md[0-9][0-9]*[ ]*:/ { print $4 }' \
392 /proc/mdstat | sort -u); do
393 case $level in
394 linear)
395 findmodule linear
396 startraid=1
397 ;;
398 raid[0145])
399 findmodule $level
400 startraid=1
401 ;;
402 *)
403 echo "raid level $level (in /proc/mdstat) not recognized" >&2
404 ;;
405 esac
406 done
407
408 if [ -n "$startraid" ]; then
409 raiddevices=$(gawk '/^md[0-9][0-9]*[ ]*:/ { print $1 }' \
410 /proc/mdstat | sort)
411 fi
412 fi
413
414 # check to see if we need to set up a loopback filesystem
415 rootdev=$(gawk '/^[ \t]*[^#]/ { if ($2 == "/") { print $1; }}' $fstab)
416 if echo $rootdev | cut -d/ -f3 | grep -q loop ; then
417 key="^# $(echo $rootdev | cut -d/ -f3 | tr '[a-z]' '[A-Z]'):"
418 if ! grep "$key" $fstab > /dev/null; then
419 echo "The root filesystem is on a $rootdev, but there is no magic entry in $fstab" 1>&2
420 echo "for this device. Consult the mkinitrd man page for more information" 2>&2
421 exit 1
422 fi
423
424 line=$(grep "$key" $fstab)
425 loopDev=$(echo $line | gawk '{print $3}')
426 loopFs=$(echo $line | gawk '{print $4}')
427 loopFile=$(echo $line | gawk '{print $5}')
428
429 basicmodules="$basicmodules -loop"
430 if [ "$loopFs" = "vfat" -o "$loopFs" = "msdos" ]; then
431 basicmodules="$basicmodules -fat"
432 fi
433 basicmodules="$basicmodules -${loopFs}"
434 # check if the root fs is on a logical volume
435 elif ! echo $rootdev | cut -c1-6 |grep -q "LABEL=" ; then
436 rootdev=$(echo "readlink $rootdev" | /sbin/nash --quiet)
437 major=`ls -l $rootdev | sed -e "s/.* \\([0-9]\+\\), *[0-9]\+.*/\\1/"`
438 [ "$major" != "58" ] || root_lvm=1
439 fi
440
441 rootfs=$(gawk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $3; }}' $fstab)
442 rootopts=$(gawk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' $fstab)
443
444 # in case the root filesystem is modular
445 findmodule -${rootfs}
446
447 if [ -n "$root_lvm" ]; then
448 findmodule -lvm-mod
449 fi
450
451 for n in $basicmodules; do
452 findmodule $n
453 done
454
455 if [ -n "$verbose" ]; then
456 echo "Using modules: $MODULES"
457 fi
458
459
460 MNTIMAGE=`mktemp -d ${TMPDIR}/initrd.XXXXXX`
461 IMAGE=`mktemp ${TMPDIR}/initrd.img.XXXXXX`
462 MNTPOINT=`mktemp -d ${TMPDIR}/initrd.mnt.XXXXXX`
463 RCFILE=$MNTIMAGE/linuxrc
464
465 if [ -z "$MNTIMAGE" -o -z "$IMAGE" -o -z "$MNTPOINT" ]; then
466 echo "Error creating temporaries. Try again" >&2
467 exit 1
468 fi
469
470 dd if=/dev/zero of=$IMAGE bs=1k count=$IMAGESIZE 2> /dev/null || exit 1
471
472 LODEV=$(echo findlodev | /sbin/nash --quiet)
473
474 if [ -z "$LODEV" ]; then
475 rm -rf $MNTIMAGE $MNTPOINT $IMAGE
476 echo "All of your loopback devices are in use." >&2
477 exit 1
478 fi
479
480 losetup ${LODEV} $IMAGE || exit 1
481
482 # We have to "echo y |" so that it doesn't complain about $IMAGE not
483 # being a block device
484 echo y | mke2fs $LODEV $IMAGESIZE >/dev/null 2>/dev/null
485 tune2fs -i0 $LODEV >/dev/null
486
487 if [ -n "$verbose" ]; then
488 echo "Using loopback device $LODEV"
489 fi
490
491 mkdir -p $MNTPOINT
492 mount -t ext2 $LODEV $MNTPOINT || {
493 echo "Can't get a loopback device"
494 exit 1
495 }
496
497 mkdir -p $MNTIMAGE
498 mkdir -p $MNTIMAGE/lib
499 mkdir -p $MNTIMAGE/bin
500 mkdir -p $MNTIMAGE/etc
501 mkdir -p $MNTIMAGE/dev
502 mkdir -p $MNTIMAGE/loopfs
503 mkdir -p $MNTIMAGE/proc
504 mkdir -p $MNTIMAGE/sysroot
505 ln -s bin $MNTIMAGE/sbin
506
507 # We don't need this directory, so let's save space
508 rm -rf $MNTPOINT/lost+found
509
510 inst /sbin/nash "$MNTIMAGE/bin/nash"
511 inst /sbin/insmod.static "$MNTIMAGE/bin/insmod"
512 ln -s /sbin/nash $MNTIMAGE/sbin/modprobe
513
514 for MODULE in $MODULES; do
515 cp $verbose -a /lib/modules/$kernel/$MODULE $MNTIMAGE/lib
516 done
517
518 # mknod'ing the devices instead of copying them works both with and
519 # without devfs...
520 mknod $MNTIMAGE/dev/console c 5 1
521 mknod $MNTIMAGE/dev/null c 1 3
522 mknod $MNTIMAGE/dev/ram b 1 1
523 mknod $MNTIMAGE/dev/systty c 4 0
524 for i in 1 2 3 4; do
525 mknod $MNTIMAGE/dev/tty$i c 4 $i
526 done
527
528 # FIXME -- this won't work if you're using devfs
529 if [ -n "$root_lvm" ]; then
530 pvs=$(/sbin/pvscan | grep " PV " | gawk {'print $5;'} |sed 's/"//g')
531 for pv in $pvs; do
532 cp $verbose --parents -a $pv $MNTIMAGE/
533 done
534
535 inst /sbin/vgwrapper "$MNTIMAGE/bin/vgwrapper"
536 ln "$MNTIMAGE/bin/vgwrapper" "$MNTIMAGE/bin/vgscan"
537 ln "$MNTIMAGE/bin/vgwrapper" "$MNTIMAGE/bin/vgchange"
538
539 mknod $MNTIMAGE/dev/lvm b 109 0
540 fi
541
542 echo "#!/bin/nash" > $RCFILE
543 echo "" >> $RCFILE
544
545 for MODULE in $MODULES; do
546 text=""
547 module=`echo $MODULE | sed "s|.*/||" | sed "s/.k\?o$//"`
548 fullmodule=`echo $MODULE | sed "s|.*/||"`
549
550 options=`sed -n -e "s/^options[ ][ ]*$module[ ][ ]*//p" $modulefile 2>/dev/null`
551
552 if [ -n "$verbose" ]; then
553 if [ -n "$options" ]; then
554 text=" with options $options"
555 fi
556 echo "Loading module $module$text"
557 fi
558 echo "echo \"Loading $fullmodule module\"" >> $RCFILE
559 echo "insmod /lib/$fullmodule $options" >> $RCFILE
560
561 # Hack - we need a delay after loading usb-storage to give things
562 # time to settle down before we start looking a block devices
563 if [ "$module" = "usb-storage" ]; then
564 echo "sleep 5" >> $RCFILE
565 fi
566 done
567
568 echo "echo Mounting /proc filesystem" >> $RCFILE
569 echo "mount -t proc /proc /proc" >> $RCFILE
570
571 if [ -n "$startraid" ]; then
572 for dev in $raiddevices; do
573 cp -a /dev/${dev} $MNTIMAGE/dev
574 echo "raidautorun /dev/${dev}" >> $RCFILE
575 done
576 fi
577
578 echo "echo Creating block devices" >> $RCFILE
579 echo "mkdevices /dev" >> $RCFILE
580
581 if [ -n "$loopDev" ]; then
582 mkdir /initrd
583 cp -a $loopDev $MNTIMAGE/dev
584 cp -a $rootdev $MNTIMAGE/dev
585 echo "echo Mounting device containing loopback root filesystem" >> $RCFILE
586 echo "mount -t $loopFs $loopDev /loopfs" >> $RCFILE
587 echo "echo Setting up loopback device $rootdev" >> $RCFILE
588 echo "losetup $rootdev /loopfs$loopFile" >> $RCFILE
589 elif [ -n "$root_lvm" ]; then
590 echo "echo Scanning logical volumes" >> $RCFILE
591 echo "vgscan" >> $RCFILE
592 echo "echo Activating logical volumes" >> $RCFILE
593 echo "vgchange -ay" >> $RCFILE
594 else
595 echo "echo Creating root device" >> $RCFILE
596 echo "mkrootdev /dev/root" >> $RCFILE
597 rootdev=/dev/root
598 fi
599
600 if [ -n "$pivot" ]; then
601 echo "echo 0x0100 > /proc/sys/kernel/real-root-dev" >> $RCFILE
602
603 echo "echo Mounting root filesystem" >> $RCFILE
604 echo "mount -o $rootopts --ro -t $rootfs $rootdev /sysroot" >> $RCFILE
605
606 echo "pivot_root /sysroot /sysroot/initrd" >> $RCFILE
607 echo "umount /initrd/proc" >> $RCFILE
608 else
609 echo "umount /proc" >> $RCFILE
610 fi
611
612 chmod +x $RCFILE
613
614 (cd $MNTIMAGE; tar cf - .) | (cd $MNTPOINT; tar xf -) || exit 1
615
616 umount $MNTPOINT
617 losetup -d $LODEV
618
619 if [ -n "$compress" ]; then
620 gzip -9 < $IMAGE > $target || rc=1
621 else
622 cp -a $IMAGE $target || rc=1
623 fi
624 rm -rf $MNTIMAGE $MNTPOINT $IMAGE
625
626 exit $rc