]> git.pld-linux.org Git - projects/geninitrd.git/blob - geninitrd
debugshell after failing to chroot.
[projects/geninitrd.git] / geninitrd
1 #!/bin/sh
2
3 # geninitrd
4 #
5 #       by PLD Linux Team
6 #
7 # based on mkinitrd from RedHat Linux
8 #
9
10 RCSID='$Revision$ $Date$'
11 R=${RCSID#* *}; VERSION=${R%% *}
12 PROGRAM=${0##*/}
13
14 . /etc/rc.d/init.d/functions
15 . /lib/geninitrd/functions
16 . /etc/sysconfig/system
17
18 # list of geninitrd modules which need setup routine after commandline args parsing
19 GENINITRD_MODS=""
20 COMPRESS=yes
21 target=""
22 kernel=""
23 force=""
24 verbose=""
25 MODULES=""
26 img_vers=""
27 fstab=/etc/fstab
28 modext=.o
29 rootdev_nr=0
30 # device node for rootfs from fstab
31 rootdev=""
32
33 # internal variables
34 # is /dev on tmpfs
35 dev_mounted=no
36 # is /proc mounted
37 proc_mounted=no
38 # is /sys mounted
39 sys_mounted=no
40 # is /tmp mounted on tmpfs
41 tmp_mounted=no
42
43 # are /dev nodes already created from /proc/devices info?
44 proc_partitions=no
45
46 usage() {
47         echo "Usage: $PROGRAM [--version] [-v] [-f] [--ifneeded] [--preload <module>]"
48         echo "       [--with=<module>] [--image-version] [--fstab=<fstab>] [--nocompress]"
49         echo "       [--compress=yes|xz|lzma|bzip2|gzip|lzo]"
50         echo "       [--initrdfs=rom|initramfs|ext2|cram] [--modules-conf=<modules.conf>]"
51         echo "       [--with-bootsplash] [--without-bootsplash]"
52         echo "       [--with-fbsplash] [--without-fbsplash]"
53         echo "       [--with-fbcondecor] [--without-fbcondecor]"
54         echo "       [--lvmtoolsversion=1|2] [--with-udev] [--without-udev]"
55         echo "       [--with-suspend] [--without-suspend]"
56         echo "       [--with-tuxonice] [--without-tuxonice]"
57         echo "       [--without-dmraid]"
58         echo "       [--with-multipath=DEVPATH] [--without-multipath]"
59         echo "       [--without-blkid] [--without-luks]"
60         echo "       <initrd-image> <kernel-version>"
61         echo ""
62         echo "Example:"
63
64         local kdir kver
65         for kdir in /lib/modules/*; do
66                 [ -d $kdir ] || continue
67                 kver=${kdir##*/}
68                 echo "  $PROGRAM -f --initrdfs=rom /boot/initrd-$kver.gz $kver"
69         done
70         exit 0
71 }
72
73 msg() {
74         echo "$PROGRAM: $*"
75 }
76
77 warn() {
78         msg "WARNING: $*" >&2
79 }
80
81 debug() {
82         [ -n "$verbose" ] && msg "$*" >&2
83 }
84
85 # aborts program abnormally
86 die() {
87         local rc=${2:-1}
88         msg "ERROR: $1" >&2
89         exit $rc
90 }
91
92 # find program from specified paths
93 find_tool() {
94         local x
95         for x in "$@"; do
96                 if [ -x "$x" ]; then
97                         echo $x
98                         debug "find_tool: found $x"
99                         return 0
100                 fi
101         done
102         debug "find_tool: did not found any of: $@"
103         return 1
104 }
105
106 # loads geninitrd modules
107 geninitrd_load_mods() {
108         local mod
109         for mod in "$@"; do
110                 if [ ! -f /lib/geninitrd/mod-$mod.sh ]; then
111                         die "$mod geninitrd module can't be loaded"
112                 fi
113                 . /lib/geninitrd/mod-$mod.sh
114
115                 if type setup_mod_$mod > /dev/null; then
116                         # add to list which need init
117                         GENINITRD_MODS="$GENINITRD_MODS $mod"
118                 fi
119         done
120 }
121
122 # setup geninitrd modules
123 geninitrd_setup_mods() {
124         local mod
125
126         for mod in $GENINITRD_MODS; do
127                 eval setup_mod_$mod
128         done
129 }
130
131 # append text to /linuxrc
132 # takes STDIN as input
133 add_linuxrc() {
134         cat >> "$RCFILE"
135 }
136
137 # generate code to mount /dev on tmpfs and create initial nodes
138 # can be called multiple times. /dev is cleaned up (umounted) automatically at
139 # the end of script.
140 mount_dev() {
141     if [ "$INITRDFS" = "initramfs" ]; then
142                 # initramfs is read-write filesystem, no need for tmpfs
143                 return
144         fi
145
146         # we already generated tmpfs code; return
147         if is_yes "$dev_mounted"; then
148                 return
149         fi
150
151         dev_mounted=yes
152
153         busybox_applet mount mknod mkdir
154         add_linuxrc <<-EOF
155                 : 'Creating /dev'
156                 mount -o mode=0755 -t tmpfs none /dev
157                 mknod /dev/console c 5 1
158                 mknod /dev/null c 1 3
159                 mknod /dev/zero c 1 5
160                 mknod /dev/random c 1 8
161                 mknod /dev/urandom c 1 9
162                 mkdir /dev/pts
163                 mkdir /dev/shm
164         EOF
165 }
166
167 # generate code to mount /proc on initrd
168 # can be called multiple times
169 mount_proc() {
170         if is_yes "$proc_mounted"; then
171                 return
172         fi
173
174         proc_mounted=yes
175     if [ "$INITRDFS" = "initramfs" ]; then
176                 # /proc is mounted with initramfs 2.6.22.14 kernel
177                 # XXX: remove when it is clear why proc was already mounted
178                 echo "[ -f /proc/cmdline ] || mount -t proc none /proc" | add_linuxrc
179         else
180                 echo "mount -t proc none /proc" | add_linuxrc
181         fi
182 }
183
184 # generate code to mount /sys on initrd
185 # can be called multiple times
186 mount_sys() {
187         if is_yes "$sys_mounted"; then
188                 return
189         fi
190
191         sys_mounted=yes
192         echo "mount -t sysfs none /sys" | add_linuxrc
193 }
194
195 # generate code to mount /tmp on initrd
196 # can be called multiple times
197 mount_tmp() {
198     if [ "$INITRDFS" = "initramfs" ]; then
199                 # initramfs is read-write filesystem, no need for tmpfs
200                 return
201         fi
202
203         if is_yes "$tmp_mounted"; then
204                 return
205         fi
206
207         tmp_mounted=yes
208         echo "mount -t tmpfs none /tmp" | add_linuxrc
209 }
210
211 # unmount all mountpoints mounted by geninitrd
212 umount_all() {
213
214         add_linuxrc <<-'EOF'
215         : Last shell before umounting all and giving control over to real init.
216         debugshell
217         EOF
218
219         if is_yes "$dev_mounted"; then
220                 echo 'umount /dev' | add_linuxrc
221                 dev_mounted=no
222         fi
223         if is_yes "$sys_mounted"; then
224                 echo 'umount /sys' | add_linuxrc
225                 sys_mounted=no
226         fi
227         if is_yes "$tmp_mounted"; then
228                 echo 'umount /tmp' | add_linuxrc
229                 tmp_mounted=no
230         fi
231         if is_yes "$proc_mounted"; then
232                 echo 'umount /proc' | add_linuxrc
233                 proc_mounted=no
234         fi
235 }
236
237
238 # Checks if busybox has support for APPLET(s)
239 # Exits from geninitrd if the support is not present.
240 #
241 # NB! XXX do not output to STDOUT, it will appear in initrd images in some cases!
242 busybox_applet() {
243         local err=0 applet
244
245         if [ -z "$busybox_functions" ]; then
246                 local tmp=$($busybox 2>&1)
247
248                 # BusyBox v1.1.3 says applet not found if it's not called 'busybox'.
249                 if [[ "$tmp" = *applet\ not\ found* ]]; then
250                         local t=$(mktemp -d)
251                         ln -s $busybox $t/busybox
252                         local tmp=$($t/busybox 2>&1)
253                         rm -rf $t
254                 fi
255
256                 busybox_functions=$(echo "$tmp" | \
257                         sed -ne '/Currently defined functions:/,$p' | \
258                         xargs | sed -e 's,.*Currently defined functions: ,,'
259                 )
260         fi
261         for applet in $*; do
262                 local have
263                 # try cache
264                 eval have='$'busybox_have_$applet
265                 if [ -z "$have" ]; then
266                         have=$(echo "$busybox_functions" | egrep -c "( |^)$applet(,|$)")
267                         if [ "$have" = 0 ]; then
268                                 warn "This setup requires busybox-initrd compiled with applet '$applet' support"
269                                 err=1
270                         fi
271                         eval busybox_have_$applet=$have
272                 fi
273         done
274         if [ $err = 1 ]; then
275                 die "Aborted"
276         fi
277 }
278
279 # Extract the .config file from a kernel image
280 # uses extract-ikconfig from kernel sources (scripts/extract-ikconfig)
281 ikconfig() {
282         local kofile=$(modinfo -k $kernel -n configs 2> /dev/null)
283         if [ -n "$kofile" ]; then
284                 /lib/geninitrd/extract-ikconfig $kofile
285         else
286                 # try vmlinuz itself
287                 /lib/geninitrd/extract-ikconfig /boot/vmlinuz-$kernel
288         fi
289 }
290
291 # Finds module dependencies
292 #
293 # @param        $module
294 #
295 # Outputs full path to module and it's dependencies
296 find_depmod() {
297         local module="$1"
298         local skiperrors=0
299
300         # if module is prefixed with dash, we should ignore errors if the module
301         # can't be found.
302         if [ ${module#-} != $module ]; then
303                 skiperrors=1
304                 module=${module#-}
305         fi
306
307         # This works when user has module-init-tools installed even on 2.4 kernels
308         local modprobe
309         modprobe=$(modprobe --set-version $kernel --show-depends $module --ignore-install 2>&1)
310
311         if [ $? != 0 ]; then
312                 if [ $skiperrors = 1 ]; then
313                         return
314                 fi
315                 echo >&2 "$modprobe"
316
317                 if ! is_no "$EXIT_IF_MISSING"; then
318                         die "$module: module not found for $kernel kernel"
319                 fi
320
321                 warn "$module: module not found for $kernel kernel"
322                 warn "If $module isn't compiled in kernel then this initrd may not start your system."
323         fi
324
325         echo "$modprobe" | \
326         while read insmod modpath options; do
327                 [ "$insmod" = "insmod" ] && echo $modpath
328         done
329 }
330
331 find_firmware() {
332         local module="$1"
333
334         # no firmware support in 2.4 kernels
335         if [ "$kernel_version_long" -lt "002005048" ]; then
336                 return
337         fi
338         echo -n $(NEW_MODINFO=1 modinfo -k $kernel -F firmware $module 2>/dev/null | xargs)
339 }
340
341 # @param        $module
342 find_module() {
343         local mod depmod module=$1
344
345         depmod=$(find_depmod $module) || exit 1
346         for mod in $depmod; do
347                 mod=${mod#/lib/modules/$kernel/}
348
349                 # add each module only once
350                 local m have=0
351                 for m in $MODULES; do
352                         [ $m = $mod ] && have=1
353                 done
354                 if [ $have = 0 ]; then
355                         MODULES="$MODULES $mod"
356                 fi
357         done
358 }
359
360 # install a file to temporary mount image.
361 # it will operate recursively (copying directories)
362 # and will symlink destinations if source is symlink.
363 inst() {
364         if [ $# -lt 2 ]; then
365                 die 'Usage: inst <file> [<file>] <destination>'
366         fi
367
368         local src i=0 c=$(($# - 1))
369         while [ $i -lt $c ]; do
370                 src="$src $1"
371                 i=$((i + 1))
372                 shift
373         done
374         local dest=$1
375         set -- $src
376         local parentDir=$(dirname $DESTDIR$dest)
377         [ ! -d "$parentDir" ] && (debug "+ mkdir -p $parentDir"; mkdir -p $parentDir)
378         debug "+ cp $* $DESTDIR$dest"
379         cp -HR "$@" "$DESTDIR$dest"
380 }
381
382 inst_d() {
383         if [ $# = 0 ]; then
384                 die 'Usage: inst_d <destination> <destination>'
385         fi
386         for dir in "$@"; do
387                 install -d "$DESTDIR$dir"
388         done
389 }
390
391 # install executable and it's shared libraries
392 inst_exec() {
393         if [ $# -lt 2 ]; then
394                 die "Invalid params ($@), Usage: inst_exec <file>[, <file>] <destination>"
395         fi
396         local src i=0 c=$(($# - 1))
397         while [ $i -lt $c ]; do
398                 src="$src $1"
399                 i=$((i + 1))
400                 shift
401         done
402         local dest=$1
403         set -- $src
404
405         inst "$@" $dest
406
407         local lib libs=$(ldd "$@" | awk '/statically|linux-(gate|vdso)\.so/{next} NF == 2 {print $1} /=/{print $3}' | sort -u)
408         for lib in $libs; do
409                 if [ ! -f "$DESTDIR/$_lib/${lib##*/}" ]; then
410                         inst_d /$_lib
411                         inst_exec $lib /$_lib
412                 fi
413         done
414
415         # hack for uclibc linked binaries requiring this fixed path
416         # XXX: shouldn't rpath be used here instead so th
417         if [ -f $DESTDIR/$_lib/libc.so.0 ]; then
418                 local lib=$DESTDIR/$_lib/libc.so.0
419                 lib=$(ldd "$lib" | awk '/statically|linux-(gate|vdso)\.so/{next} NF == 2 {print $1} /=/{print $3}' | sort -u)
420                 local libdir=$(cd $(dirname "$lib"); pwd)
421                 if [ ! -e $DESTDIR$libdir ]; then
422                         libdir=$(dirname "$libdir")
423                         inst_d $libdir
424                         debug "+ ln -s /$_lib $DESTDIR$libdir"
425                         ln -s /$_lib $DESTDIR$libdir
426                 fi
427         fi
428 }
429
430 # output modules.conf / modprobe.conf
431 modprobe_conf() {
432         echo "$modprobe_conf_cache"
433 }
434
435 #
436 # defaults to modprobe -c if not told otherwise, this means include statements
437 # work from there.
438 cache_modprobe_conf() {
439         if [ "$kernel_version" -lt "002005" ]; then
440                 modulefile=/etc/modules.conf
441                 if [ ! -f "$modulefile" -a -f /etc/conf.modules ]; then
442                         modulefile=/etc/conf.modules
443                 fi
444         fi
445
446         if [ -n "$modulefile" ]; then
447                 debug "Using $modulefile for modules config"
448                 modprobe_conf_cache=$(cat $modulefile)
449         else
450                 debug "Using modprobe -c to get modules config"
451                 modprobe_conf_cache=$(modprobe -c --set-version $kernel)
452         fi
453 }
454
455 # find modules for $devpath
456 find_modules_for_devpath() {
457         local devpath="$1"
458         if [ -z "$devpath" ]; then
459                 die "No argument passed to find_modules_for_devpath() - is your /etc/fstab correct?"
460         fi
461
462         if [[ "$devpath" = /dev/dm-* ]]; then
463                 # /dev/dm-3 -> /dev/mapper/sil_ahbgadcbchfc3
464                 devpath=$(dm_node "$devpath")
465         fi
466
467         if [ -L "$devpath" ] && ! is_lvm "$devpath"; then
468                 # sanitize things like:
469                 # /dev/block/104:2 -> /dev/cciss/c0d0p2
470                 devpath=$(readlink -f "$devpath")
471         fi
472
473         debug "Finding modules for device path $devpath"
474
475         if is_luks "$devpath"; then
476                 find_modules_luks "$devpath"
477                 return
478         fi
479
480         if is_nfs "$devpath"; then
481                 find_modules_nfs "$devpath"
482                 return
483         fi
484
485         if is_md "$devpath"; then
486                 find_modules_md "$devpath"
487                 return
488         fi
489
490         if is_multipath "$devpath"; then
491                 if find_modules_multipath "$devpath"; then
492                         return
493                 fi
494
495                 # fallback
496         fi
497
498         if is_dmraid "$devpath"; then
499                 if find_modules_dmraid "$devpath"; then
500                         return
501                 fi
502                 # fallback
503         fi
504
505         if is_scsi "$devpath"; then
506                 find_modules_scsi "$devpath"
507                 return
508         fi
509
510         if is_ide "$devpath"; then
511                 find_modules_ide "$devpath"
512                 return
513         fi
514
515         if [[ "$devpath" == /dev/rd/* ]]; then
516                 find_module "DAC960"
517                 rootdev_add=/dev/rd/
518                 return
519         fi
520
521         if [[ "$devpath" == /dev/ida/* ]]; then
522                 find_module "cpqarray"
523                 rootdev_add=/dev/ida/
524                 return
525         fi
526
527         if [[ "$devpath" == /dev/cciss/* ]]; then
528                 find_module "cciss"
529                 rootdev_add=/dev/cciss/
530                 return
531         fi
532
533         if [[ "$devpath" == /dev/ataraid/* ]]; then
534                 find_modules_ide
535                 find_module "ataraid"
536                 ataraidmodules=$(modprobe_conf | awk '/ataraid_hostadapter/ && ! /^[\t ]*#/ { print $3; }')
537                 if [ -n "$ataraidmodules" ]; then
538                         # FIXME: think about modules compiled in kernel
539                         die "ataraid_hostadapter alias not defined in modprobe.conf! Please set it and run $PROGRAM again."
540                 fi
541                 for n in $ataraidmodules; do
542                         find_module "$n"
543                 done
544                 rootdev_add=/dev/ataraid/
545                 return
546         fi
547
548         # check to see if we need to set up a loopback filesystem
549         if [[ "$devpath" == /dev/loop*  ]]; then
550                 die "Sorry, root on loop device isn't supported."
551                 # TODO: rewrite for bsp and make nfs ready
552                 if [ ! -x /sbin/losetup ]; then
553                         die "losetup is missing"
554                 fi
555                 key="^# $(echo $devpath | awk -F/ '{print($3);}' | tr '[a-z]' '[A-Z]'):"
556                 if ! is_yes "`awk '/'$key'/ { print( "yes"); }' $fstab`"; then
557                         die "The root filesystem is on a $devpath, but there is no magic entry in $fstab for this device. Consult the $PROGRAM man page for more information"
558                 fi
559
560                 line="`awk '/'$key'/ { print $0; }' $fstab`"
561                 loopDev="$(echo $line | awk '{print $3}')"
562                 loopFs="$(echo $line | awk '{print $4}')"
563                 loopFile="$(echo $line | awk '{print $5}')"
564
565                 BASICMODULES="$BASICMODULES -loop"
566                 find_module "-$loopFs"
567                 BASICMODULES="$BASICMODULES -${loopFs}"
568                 return
569         fi
570
571         if is_lvm "$devpath"; then
572                 find_modules_lvm "$devpath"
573                 return
574         fi
575 }
576
577 firmware_install_module() {
578         local module="$1"
579         local firmware_files="$2"
580
581         debug "Adding Firmwares ($firmware_files) to initrd for module $module"
582         # firmware not yet installed
583         if [ ! -f "$DESTDIR/lib/firmware/firmware.sh" ]; then
584                 inst_d /lib/firmware
585 cat << 'EOF' >> "$DESTDIR/lib/firmware/firmware.sh"
586 #!/bin/sh -e
587 echo 1 > /sys$DEVPATH/loading
588 cat "/lib/firmware/$FIRMWARE" > /sys$DEVPATH/data
589 echo 0 > /sys$DEVPATH/loading
590 exit 0
591 EOF
592                 chmod 755 "$DESTDIR/lib/firmware/firmware.sh"
593         fi
594
595         for firmware in $firmware_files; do
596                 if [ -f "/lib/firmware/$kernel/$firmware" ]; then
597                         FIRMWAREDIR=${firmware%/*}
598                         [ "$FIRMWAREDIR" != "$firmware" ] && inst_d /lib/firmware/$FIRMWAREDIR
599                         inst /lib/firmware/$kernel/$firmware /lib/firmware/$firmware
600                 elif [ -f "/lib/firmware/$firmware" ]; then
601                         FIRMWAREDIR=${firmware%/*}
602                         [ "$FIRMWAREDIR" != "$firmware" ] && inst_d /lib/firmware/$FIRMWAREDIR
603                         inst /lib/firmware/$firmware /lib/firmware/$firmware
604                 else
605                         die "firmware file /lib/firmware/$firmware nor /lib/firmware/$kernel/$firmware found."
606                 fi
607         done
608
609         mount_sys
610         echo "echo -n "/lib/firmware/firmware.sh" > /proc/sys/kernel/hotplug" | add_linuxrc
611 }
612
613 modules_install() {
614         local modules="$1"
615         local mod
616
617         for mod in $modules; do
618                 MODULEDIR=${mod%/*}
619                 inst_d "/lib/modules/$kernel/$MODULEDIR"
620                 cp -a "/lib/modules/$kernel/$mod" "$DESTDIR/lib/modules/$kernel/$mod"
621                 gunzip "$DESTDIR/lib/modules/$kernel/$mod" 2> /dev/null
622         done
623 }
624
625 modules_add_linuxrc() {
626         local mod modpath
627
628         for mod in "$@"; do
629                 # module path without optional compression
630                 modpath=${mod%.gz}
631
632                 # name of the module
633                 local module=${modpath##*/}; module=${module%$modext}
634                 local options=$(modprobe_conf | awk -vmodule="$module" '{ if ($1 == "options" && $2 == module) { for(i=3;i<=NF;i++) printf("%s ",$i); }}' | xargs)
635                 local genericname=$(echo $module | tr - _)
636                 local usleep=$(eval echo \$MODULE_${genericname}_USLEEP)
637                 local firmware=$(eval echo \$MODULE_${genericname}_FIRMWARE)
638
639                 if [ "$module" = "scsi_mod" -a "$kernel_version_long" -ge "002006030" ]; then
640                         options="scan=sync $options"
641                 fi
642
643                 if [ -n "$verbose" ]; then
644                         s=""
645                         if [ "$options" ]; then
646                                 s="$s with options [$options]"
647                         fi
648                         if [ "$usleep" ]; then
649                                 s="$s and $usleep usleep"
650                         fi
651                         debug "Loading module [$module]$s"
652                 fi
653
654                 if [ -n "$firmware" ]; then
655                         firmware_install_module "$module" "$firmware"
656                 else
657                         for file in $(find_firmware "$module"); do
658                                 firmware_install_module "$module" "$file"
659                         done
660                 fi
661
662                 echo "insmod /lib/modules/$kernel/$modpath $options" | add_linuxrc
663                 if [ -n "$usleep" ]; then
664                         echo "usleep $usleep" | add_linuxrc
665                 fi
666                 if [ "$module" = "scsi_wait_scan" ]; then
667                         if [ "$(busybox_applet rmmod 2>/dev/null; echo $?)" = 0 ]; then
668                                 echo "rmmod scsi_wait_scan" | add_linuxrc
669                         fi
670                 fi
671
672         done
673 }
674
675 # Generates /dev nodes based on /proc/partitions information.
676 # Needs /proc mounted.
677 # Can be called multiple times.
678 initrd_gen_devices() {
679         if is_yes "$proc_partitions"; then
680                 return
681         fi
682         proc_partitions=yes
683
684         mount_dev
685         add_linuxrc <<-'EOF'
686                 : 'Making device nodes'
687                 cat /proc/partitions | (
688                         # ignore first two lines: header, empty line
689                         read b; read b
690
691                         while read major minor blocks dev rest; do
692                                 node=/dev/$dev
693                                 mkdir -p ${node%/*}
694                                 [ -e $node ] || mknod $node b $major $minor
695                         done
696                 )
697         EOF
698 }
699
700
701 initrd_gen_setrootdev() {
702         debug "Adding rootfs finding based on kernel cmdline root= option support."
703         add_linuxrc <<-'EOF'
704                 if [ "${ROOT##/dev/}" != "${ROOT}" ]; then
705                         rootnr="$(busybox awk -v rootnode="${ROOT##/dev/}" '$4 == rootnode { print 256 * $1 + $2 }' /proc/partitions)"
706                         if [ -n "$rootnr" ]; then
707                                 echo "$rootnr" > /proc/sys/kernel/real-root-dev
708                         fi
709                 fi
710         EOF
711 }
712
713 initrd_gen_initramfs_switchroot() {
714         inst_d /newroot
715         if [ "$rootdev" = "/dev/nfs" ]; then
716                 echo "rootfs on NFS root=/dev/nfs"
717         else
718                 [ ! -e "$DESTDIR/$rootdev" ] && inst $rootdev $rootdev
719         fi
720
721         # parse 'root=xxx' kernel commandline
722         # We support passing root as hda3 /dev/hda3 0303 0x0303 and 303
723         add_linuxrc <<-'EOF'
724                 device=/dev/no_partition_found
725                 eval "$(busybox awk -v c="$ROOT" '
726                         BEGIN {
727                                 num_pattern_short = "[0-9a-f][0-9a-f][0-9a-f]";
728                                 num_pattern = "[0-9a-f]" num_pattern_short;
729                                 dev_pattern = "[hms][a-z][a-z]([0-9])+";
730                                 partition = "no_partition_found";
731                                 min = -1; maj = -1;
732
733                                 sub("^0x", "", c);
734                                 if (c ~ "^" num_pattern_short "$") sub("^", "0", c);
735                                 if (c ~ "^" num_pattern  "$") {
736                                         maj = sprintf("%s",substr(c,1,2));
737                                         min = sprintf("%s",substr(c,3));
738                                 }
739                                 if (c ~ "^\/dev\/" dev_pattern "$") sub("^/dev/","", c);
740                                 if (c ~ "^" dev_pattern "$") partition = c;
741                         }
742
743                         $4 ~ partition { maj = $1; min = $2; }
744                         $1 ~ maj && $2 ~ min { partition = $4; }
745
746                         END {
747                                 if (maj >= 0 && min >= 0) {
748                                         printf("device=/dev/%s; maj=%s; min=%s;\n", partition, maj, min);
749                                 }
750                         }
751                         ' /proc/partitions)"
752                 if [ "$device" != '/dev/no_partition_found' -a ! -b $device ]; then
753                         mknod $device b $maj $min
754                 fi
755         EOF
756
757         add_linuxrc <<-EOF
758                 rootdev=$rootdev
759                 rootfs=$rootFs
760         EOF
761
762         add_linuxrc <<-'EOF'
763                 if [ "$device" = '/dev/no_partition_found' ]; then
764                         device=$rootdev
765                 fi
766
767                 [ -n "$ROOTFSFLAG" ] && ROOTFSFLAGS="-o $ROOTFSFLAGS"
768
769                 mount -t $rootfs -r $device $ROOTFSFLAGS /newroot
770                 init="$(echo "$CMDLINE" | busybox awk '/init=\// { gsub(/.*init=/,NIL,$0); gsub(/ .*/,NIL,$0); print }')"
771                 if [ -z "$init" -o ! -x "/newroot$init" ]; then
772                         init=/sbin/init
773                 fi
774         EOF
775
776         umount_all
777         busybox_applet switch_root
778         add_linuxrc <<-'EOF'
779                 exec switch_root /newroot $init ${1:+"$@"}
780
781                 echo "Error! initramfs should not reach this place."
782                 echo "It probably means you've got old version of busybox, with broken"
783                 echo "initramfs support. Trying to boot anyway, but won't promise anything."
784
785                 exec chroot /newroot $init ${1:+"$@"}
786
787                 echo "Failed to chroot!"
788                 debugshell
789         EOF
790         # we need /init being real file, not symlink, otherwise the initramfs will
791         # not be ran by pid 1 which is required for switch_root
792         mv $DESTDIR/linuxrc $DESTDIR/init
793         ln -s init $DESTDIR/linuxrc
794 }
795
796 # find if $symbol exists in System.map $mapfile
797 sym_exists() {
798         local mapfile="$1"
799         local symbol="$2"
800         if [ ! -f $mapfile ]; then
801                 # missing mapfile (not a pld kernel?)
802                 return 1
803         fi
804
805         awk -vc=1 -vsymbol="$symbol" '$2 == "T" && $3 == symbol {c = 0} END {exit c}' $mapfile
806 }
807
808 # find best compressor (or forced one) for initrd
809 find_compressor() {
810         local mode="$1"
811         # fastest initrd decompression speed is first
812         local compressors='lzo gzip xz lzma bzip2'
813
814         # a specified one, take it
815         if ! is_yes "$mode"; then
816                 compressors="$mode"
817         fi
818
819         debug "finding compressor: $compressors (via $mode)"
820         # check for compressor validity
821         local c prog map=/boot/System.map-$kernel
822         for c in $compressors; do
823                 case $c in
824                 xz)
825                         sym=unxz
826                         prog=/usr/bin/xz
827                         ;;
828                 lzma)
829                         sym=unlzma
830                         prog=/usr/bin/xz
831                         ;;
832                 bzip2)
833                         sym=bzip2
834                         prog=/usr/bin/bzip2
835                         ;;
836                 gzip)
837                         sym=gunzip
838                         prog=/bin/gzip
839                         ;;
840                 lzo)
841                         sym=unlzo
842                         prog=/usr/bin/lzop
843                         ;;
844                 none|no)
845                         # any existing sym will work
846                         sym=initrd_load
847                         prog=/bin/cat
848                         ;;
849                 *)
850                         die "Unknown compressor $c"
851                         ;;
852                 esac
853                 if sym_exists $map $sym && [ -x $prog ]; then
854                         echo $c
855                         return
856                 fi
857         done
858
859         debug "using gzip for compressor (fallback)"
860         echo gzip
861 }
862
863 # compresses kernel image image
864 # in function so we could retry with other compressor on failure
865 compress_image() {
866         local compressor="$1" IMAGE="$2" target="$3" tmp
867         tmp=$(mktemp "$target".XXXXXX) || die "mktemp failed"
868
869         case "$compressor" in
870         xz)
871                 # don't use -9 here since kernel won't understand it
872                 xz --format=xz --check=crc32 --lzma2=preset=6e,dict=1MiB < "$IMAGE" > "$tmp" || return $?
873                 ;;
874         lzma)
875                 xz --format=lzma -9 < "$IMAGE" > "$tmp" || return $?
876                 ;;
877         bzip2)
878                 bzip2 -9 < "$IMAGE" > "$tmp" || return $?
879                 ;;
880         gzip)
881                 gzip -9 < "$IMAGE" > "$tmp" || return $?
882                 ;;
883         lzo)
884                 lzop -9 < "$IMAGE" > "$tmp" || return $?
885                 ;;
886         none|no)
887                 cat < "$IMAGE" > "$tmp" || return $?
888                 ;;
889         esac
890
891         mv -f "$tmp" "$target"
892 }
893
894 if [ -r /etc/sysconfig/geninitrd ]; then
895         . /etc/sysconfig/geninitrd
896 fi
897
898 if [ ! -f /proc/mounts ]; then
899         warn "/proc filesystem not mounted, may cause wrong results or failure."
900 fi
901
902 geninitrd_load_mods ide luks multipath dmraid lvm md blkid udev tuxonice suspend fbsplash condecor bootsplash uvesafb nfs sata scsi
903
904 while [ $# -gt 0 ]; do
905         case $1 in
906         --fstab=*)
907                 fstab=${1#--fstab=}
908                 ;;
909         --fstab)
910                 fstab=$2
911                 shift
912                 ;;
913         --modules-conf=*)
914                 modulefile=${1#--modules-conf=}
915                 ;;
916         --modules-conf)
917                 modulefile=$2
918                 shift
919                 ;;
920         --with-bootsplash)
921                 BOOT_SPLASH=yes
922                 ;;
923         --without-bootsplash)
924                 BOOT_SPLASH=no
925                 ;;
926         --with-fbsplash)
927                 FB_SPLASH=yes
928                 ;;
929         --without-fbsplash)
930                 FB_SPLASH=no
931                 ;;
932         --with-fbcondecor)
933                 FB_CON_DECOR=yes
934                 ;;
935         --without-fbcondecor)
936                 FB_CON_DECOR=no
937                 ;;
938         --with-suspend)
939                 USE_SUSPEND=yes
940                 ;;
941         --without-suspend)
942                 USE_SUSPEND=no
943                 ;;
944         --with-suspend2 | --with-tuxonice)
945                 USE_TUXONICE=yes
946                 ;;
947         --without-suspend2 | --without-tuxonice)
948                 USE_TUXONICE=no
949                 ;;
950         --lvmversion=*)
951                 LVMTOOLSVERSION=${1#--lvmversion=}
952                 ;;
953         --lvmtoolsversion=*)
954                 LVMTOOLSVERSION=${1#--lvmtoolsversion=}
955                 ;;
956         --lvmtoolsversion|--lvmversion)
957                 LVMTOOLSVERSION=$2
958                 shift
959                 ;;
960         --without-udev)
961                 USE_UDEV=no
962                 ;;
963         --with-udev)
964                 USE_UDEV=yes
965                 ;;
966         --without-dmraid)
967                 USE_DMRAID=no
968                 ;;
969         --without-multipath)
970                 USE_MULTIPATH=no
971                 ;;
972         --with-multipath=*)
973                 USE_MULTIPATH=${1#--with-multipath=}
974                 ;;
975         --without-blkid)
976                 USE_BLKID=no
977                 ;;
978         --without-luks)
979                 USE_LUKS=no
980                 ;;
981         --with=*)
982                 BASICMODULES="$BASICMODULES ${1#--with=}"
983                 ;;
984         --with)
985                 BASICMODULES="$BASICMODULES $2"
986                 shift
987                 ;;
988         --version)
989                 echo "$PROGRAM: version $VERSION"
990                 exit 0
991                 ;;
992         -v)
993                 verbose=-v
994                 ;;
995         --compress)
996                 COMPRESS=$2
997                 ;;
998         --compress=*)
999                 COMPRESS="${1#--compress=}"
1000                 ;;
1001         --nocompress)
1002                 COMPRESS=no
1003                 ;;
1004         --ifneeded)
1005                 ifneeded=1
1006                 ;;
1007         -f)
1008                 force=1
1009                 ;;
1010         --preload=*)
1011                 PREMODS="$PREMODS ${1#--preload=}"
1012                 ;;
1013         --preload)
1014                 PREMODS="$PREMODS $2"
1015                 shift
1016                 ;;
1017         --fs=* | --fs)
1018                 die "--fs option is obsoleted. Use --initrdfs instead"
1019                 ;;
1020         --initrdfs=*)
1021                 INITRDFS=${1#--initrdfs=}
1022                 ;;
1023         --initrdfs)
1024                 INITRDFS=$2
1025                 shift
1026                 ;;
1027         --image-version)
1028                 img_vers=yes
1029                 ;;
1030         --ide-only-root)
1031                 ide_only_root="yes"
1032                 ;;
1033         *)
1034                 if [ -z "$target" ]; then
1035                         target="$1"
1036                 elif [ -z "$kernel" ]; then
1037                         kernel="$1"
1038                 else
1039                         usage >&2
1040                         exit 1
1041                 fi
1042                 ;;
1043         esac
1044
1045         shift
1046 done
1047
1048 if [ -z "$target" -o -z "$kernel" ]; then
1049         usage >&2
1050         exit 1
1051 fi
1052
1053 # main()
1054 if [ "$(id -u)" != 0 ]; then
1055         die "You need to be root to generate initrd"
1056 fi
1057
1058 if [ -d /lib64 -a -d /usr/lib64 ]; then
1059         _lib=lib64
1060 else
1061         _lib=lib
1062 fi
1063
1064 initrd_dir=/usr/$_lib/initrd
1065 kernel_version=$(echo "$kernel" | awk -F. '{print sprintf("%03d%03d",$1,$2)}')
1066 kernel_version_long=$(echo "$kernel" | awk -F. '{print sprintf("%03d%03d%03d",$1,$2,$3)}')
1067
1068 debug "# $RCSID"
1069 debug "Using _lib: $_lib"
1070 debug "Using initrd_dir: $initrd_dir"
1071
1072 busybox=$(find_tool $initrd_dir/busybox $initrd_dir/initrd-busybox /bin/initrd-busybox) || die "Couldn't find busybox suitable for initrd"
1073
1074 # we setup mods after parsing command line args
1075 geninitrd_setup_mods
1076
1077 if [ ! -f /boot/vmlinuz-"$kernel" ]; then
1078         warn "/boot/vmlinuz-$kernel doesn't exist, is your /boot mounted?"
1079 fi
1080
1081 if [ -z "$INITRDFS" ]; then
1082         if [ -n "$FS" ]; then
1083                 # FS= can came only via /etc/sysconfig/geninitrd likely?
1084                 die "FS configuration option is obsoleted. Use INITRDFS instead"
1085         fi
1086
1087         # default value
1088         if [ "$kernel_version" -ge "002005" ]; then
1089                 INITRDFS="initramfs"
1090         else
1091                 INITRDFS="rom"
1092         fi
1093 fi
1094
1095 case "$INITRDFS" in
1096   ext2)
1097         [ -x /sbin/mke2fs ] || die "/sbin/mke2fs is missing"
1098         ;;
1099   rom|romfs)
1100         [ -x /sbin/genromfs ] || die "/sbin/genromfs is missing"
1101         ;;
1102   cram|cramfs)
1103         [ -x /sbin/mkcramfs ] || die "/sbin/mkcramfs is missing"
1104         ;;
1105   initramfs)
1106         [ -x /bin/cpio ] || die "/bin/cpio is missing"
1107         [ -x /usr/bin/find ] || die "/usr/bin/find is missing"
1108         ;;
1109   *)
1110         die "Filesystem $INITRDFS on initrd is not supported"
1111         ;;
1112 esac
1113
1114 if [ -L "$target" ]; then
1115         target=$(readlink -f "$target")
1116 fi
1117
1118 if [ -n "$img_vers" ]; then
1119         target="$target-$kernel"
1120 fi
1121
1122 if [ -z "$force" -a -f "$target" ]; then
1123         die "$target already exists."
1124 fi
1125
1126 if [ ! -d "/lib/modules/$kernel" ]; then
1127         die "/lib/modules/$kernel is not a directory."
1128 fi
1129
1130 if [ "$kernel_version" -ge "002005" ]; then
1131         modext=".ko"
1132 fi
1133
1134 cache_modprobe_conf
1135
1136 for n in $PREMODS; do
1137         find_module "$n"
1138 done
1139
1140 if [ "$FBMODULE" ]; then
1141         find_module "$FBMODULE"
1142 fi
1143
1144 # allow forcing loading SCSI and/or IDE modules
1145 # XXX: where ADDSCSI cames from? drop?
1146 if is_yes "$ADDSCSI"; then
1147         find_modules_scsi
1148 fi
1149
1150 # autodetect SATA modules
1151 find_modules_sata
1152
1153 # XXX: where ADDIDE cames from? drop?
1154 if is_yes "$ADDIDE"; then
1155         find_modules_ide
1156 fi
1157
1158 if is_yes "$USE_SUSPEND"; then
1159         find_modules_suspend
1160 fi
1161
1162 find_root "$fstab" || exit
1163 debug "Using $rootdev as device for rootfs"
1164
1165 find_modules_for_devpath "$rootdev"
1166
1167 # if USE_MULTIPATH is path to device, scan that too
1168 # this is to bootstrap multipath setup into initrd.
1169 if ! is_no "$USE_MULTIPATH" && ! is_yes "$USE_MULTIPATH"; then
1170         find_modules_multipath $USE_MULTIPATH
1171 fi
1172
1173 find_module "-$rootFs"
1174
1175 for n in $BASICMODULES; do
1176         find_module "$n"
1177 done
1178
1179 if is_yes "$USE_TUXONICE"; then
1180         find_module "-lzf"
1181 fi
1182
1183 find_modules_fbsplash
1184
1185 if [ -n "$ifneeded" -a -z "$MODULES" ]; then
1186         debug "No modules are needed -- not building initrd image."
1187         exit 0
1188 fi
1189
1190 debug "Building initrd..."
1191 DESTDIR=$(mktemp -d -t initrd.XXXXXX) || die "mktemp failed"
1192 RCFILE="$DESTDIR/linuxrc"
1193 > "$RCFILE"
1194 chmod a+rx "$RCFILE"
1195 ln -s linuxrc $DESTDIR/init
1196
1197 # create dirs that we really need
1198 inst_d /{lib,bin,etc,dev{,/pts,/shm},loopfs,var,proc,sys}
1199
1200 modules_install "$MODULES"
1201
1202 # mknod'ing the devices instead of copying them works both with and
1203 # without devfs...
1204 mknod "$DESTDIR/dev/console" c 5 1
1205 mknod "$DESTDIR/dev/null" c 1 3
1206 mknod "$DESTDIR/dev/zero" c 1 5
1207 mknod "$DESTDIR/dev/random" c 1 8
1208 mknod "$DESTDIR/dev/urandom" c 1 9
1209
1210 inst_exec $busybox /bin/busybox
1211 ln -s busybox $DESTDIR/bin/sh
1212 # for older busyboxes who had /bin/initrd-busybox as EXEPATH
1213 ln -s busybox $DESTDIR/bin/initrd-busybox
1214
1215 add_linuxrc <<EOF
1216 #!/bin/sh
1217 # initrd generated by:
1218 # $RCSID
1219
1220 EOF
1221 mount_proc
1222 add_linuxrc <<-'EOF'
1223         read CMDLINE < /proc/cmdline; export CMDLINE
1224
1225         for arg in $CMDLINE; do
1226                 if [ "${arg}" = "debuginitrd" ]; then
1227                         DEBUGINITRD=yes
1228                 fi
1229                 if [ "${arg##debuginitrd=}" != "${arg}" ]; then
1230                         DEBUGINITRD=${arg##debuginitrd=}
1231                 fi
1232                 if [ "${arg##root=}" != "${arg}" ]; then
1233                         ROOT=${arg##root=}
1234                 fi
1235                 if [ "${arg##rootfsflags=}" != "${arg}" ]; then
1236                         ROOTFSFLAGS=${arg##rootfsflags=}
1237                 fi
1238         done
1239
1240         # make debugshell() invoke subshell if $DEBUGINITRD=sh
1241         if [ "$DEBUGINITRD" = "sh" ]; then
1242                 debugshell() {
1243 EOF
1244 if is_yes "$RUN_SULOGIN_ON_ERR"; then
1245 add_linuxrc <<-'EOF'
1246         echo "debug shell disabled by /etc/sysconfig/system:RUN_SULOGIN_ON_ERR setting"
1247 EOF
1248 else
1249 add_linuxrc <<-'EOF'
1250         sh
1251 EOF
1252 fi
1253 add_linuxrc <<-'EOF'
1254                 }
1255         else
1256                 debugshell() {
1257                         :
1258                 }
1259         fi
1260
1261         if [ "$DEBUGINITRD" ]; then
1262                 set -x
1263         fi
1264 EOF
1265
1266 modules_add_linuxrc $MODULES
1267
1268 # TODO: rewrite for busybox
1269 #if [ -n "$loopDev" ]; then
1270 #       if [ ! -d /initrd ]; then
1271 #               mkdir /initrd
1272 #       fi
1273 #
1274 #       cp -a "$loopDev" "$DESTDIR/dev"
1275 #       cp -a "$rootdev" "$DESTDIR/dev"
1276 #       echo "echo Mounting device containing loopback root filesystem" >> "$RCFILE"
1277 #       echo "mount -t $loopFs $loopDev /loopfs" >> "$RCFILE"
1278 #       echo "echo Setting up loopback device $rootdev" >> $RCFILE
1279 #       echo "losetup $rootdev /loopfs$loopFile" >> "$RCFILE"
1280 #fi
1281
1282 if is_yes "$USE_UDEV"; then
1283         initrd_gen_udev
1284 fi
1285
1286 find_modules_uvesafb
1287 initrd_gen_uvesafb
1288
1289 initrd_gen_luks
1290 initrd_gen_dmraid
1291 initrd_gen_multipath
1292 initrd_gen_blkid
1293
1294 if is_yes "$have_nfs"; then
1295         initrd_gen_nfs
1296 else
1297         initrd_gen_md
1298         initrd_gen_lvm
1299         initrd_gen_luks
1300         initrd_gen_setrootdev
1301 fi
1302
1303 initrd_gen_tuxonice
1304 initrd_gen_suspend
1305
1306 # additional devs always needed
1307 [ ! -e "$DESTDIR/$rootdev_add" ] && inst $rootdev_add /dev
1308
1309 initrd_gen_stop_udevd
1310
1311 if [ "$INITRDFS" = "initramfs" ]; then
1312         initrd_gen_initramfs_switchroot
1313 else
1314         umount_all
1315 fi
1316
1317 initrd_gen_fbsplash
1318 initrd_gen_fbcondecor
1319
1320 IMAGE=$(mktemp -t initrd.img-XXXXXX) || die "mktemp failed"
1321
1322 debug "Creating $INITRDFS image $IMAGE"
1323 case "$INITRDFS" in
1324   ext2)
1325         dd if=/dev/zero of="$IMAGE" bs=1k count="$IMAGESIZE" 2> /dev/null
1326         mke2fs -q -F -b 1024 -m 0 "$IMAGE" 2>/dev/null 1>&2
1327         tune2fs -i 0 "$IMAGE" >/dev/null 2>&1
1328
1329         local tmpmnt=$(mktemp -d -t initrd.mnt-XXXXXX)
1330         debug "Mounting ext2 image $IMAGE to $tmpmnt"
1331         mount -o loop -t ext2 "$IMAGE" "$tmpmnt"
1332         # We don't need this directory, so let's save space
1333         rm -rf "$tmpmnt"/lost+found
1334
1335         debug "Copy recursively $DESTDIR -> $tmpmnt"
1336         cp -a $DESTDIR/* $tmpmnt
1337         umount "$IMAGE"
1338         rmdir "$tmpmnt"
1339
1340         ;;
1341   rom|romfs)
1342         genromfs -f "$IMAGE" -d "$DESTDIR" -V "PLD Linux/$kernel initrd"
1343         ;;
1344   cram|cramfs)
1345         mkcramfs "$DESTDIR" "$IMAGE"
1346         ;;
1347   initramfs)
1348         (cd $DESTDIR; find . | cpio --quiet -H newc -o > "$IMAGE")
1349         ;;
1350   *)
1351         die "Filesystem $INITRDFS not supported by $PROGRAM"
1352 esac
1353
1354 CONFIG_BLK_DEV_RAM_SIZE=$(ikconfig | awk -F= '/^CONFIG_BLK_DEV_RAM_SIZE/{print $2}')
1355 if [ -z "$CONFIG_BLK_DEV_RAM_SIZE" ]; then
1356         CONFIG_BLK_DEV_RAM_SIZE=4096
1357 fi
1358
1359 IMAGESIZE=$(du -ks $DESTDIR | awk '{print int(($1+1023+512)/1024)*1024}')
1360 debug   "image size: $IMAGESIZE KiB ($DESTDIR)"
1361 if [ "$IMAGESIZE" -gt $CONFIG_BLK_DEV_RAM_SIZE ]; then
1362         warn "Your image size is larger than $CONFIG_BLK_DEV_RAM_SIZE, Be sure to boot kernel with ramdisk_size=$IMAGESIZE!"
1363 fi
1364
1365 if ! is_no "$COMPRESS"; then
1366         compressor=$(find_compressor "$COMPRESS")
1367         debug "Compressing $target with $compressor"
1368
1369         # TODO: the image name (specified from kernel.spec) already contains
1370         # extension, which is .gz most of the time.
1371         compress_image "$compressor" "$IMAGE" "$target" || {
1372                 if [ $compressor != gzip ]; then
1373                         warn "Could not compress with $compressor, retrying with gzip"
1374                         compress_image gzip "$IMAGE" "$target" || die "compress failed with gzip" $?
1375                 else
1376                         die "Could not compress image with $compressor"
1377                 fi
1378         }
1379 else
1380         cp -a "$IMAGE" "$target"
1381 fi
1382
1383 # XXX. check if bootsplash can output data to tmp dir not directly to initramfs image.
1384 initrd_gen_bootsplash "$target"
1385
1386 rm -rf "$DESTDIR" "$IMAGE"
1387
1388 # vim:ts=4:sw=4:noet:fdm=marker
This page took 0.160709 seconds and 4 git commands to generate.