]> git.pld-linux.org Git - projects/geninitrd.git/blob - geninitrd
432999c1214f43c9b1508bded01254bf1abb4dac
[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 VERSION='devel'
11 PROGRAM=${0##*/}
12
13 . /etc/rc.d/init.d/functions
14 . /lib/geninitrd/functions
15 . /etc/sysconfig/system
16
17 # list of geninitrd modules which need setup routine after commandline args parsing
18 GENINITRD_MODS=""
19 COMPRESS=yes
20 STRIP=/usr/bin/strip
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 "       [--nostrip ] [--strip PATH/strip] [--strip=PATH/strip]"
51         echo "       [--initrdfs=rom|initramfs|ext2|cram] [--modules-conf=<modules.conf>]"
52         echo "       [--with-bootsplash] [--without-bootsplash]"
53         echo "       [--with-fbsplash] [--without-fbsplash]"
54         echo "       [--with-fbcondecor] [--without-fbcondecor]"
55         echo "       [--lvmtoolsversion=1|2] [--with-udev] [--without-udev]"
56         echo "       [--with-suspend] [--without-suspend]"
57         echo "       [--with-tuxonice] [--without-tuxonice]"
58         echo "       [--without-dmraid]"
59         echo "       [--with-multipath=DEVPATH] [--without-multipath]"
60         echo "       [--without-blkid] [--without-luks]"
61         echo "       <initrd-image> <kernel-version>"
62         echo ""
63         echo "Example:"
64
65         local kdir kver dir=${target:-/boot}
66         for kdir in /lib/modules/*; do
67                 [ -d $kdir ] || continue
68                 kver=${kdir##*/}
69                 echo "  $0 -f --initrdfs=initramfs $dir/initrd-$kver.gz $kver $verbose"
70         done | sort -V
71 }
72
73 msg() {
74         echo "$PROGRAM: $*"
75 }
76
77 warn() {
78         msg "WARNING: $*" >&2
79 }
80
81 verbose() {
82         [ -n "$verbose" ] && msg "$*" >&3
83 }
84
85 debug() {
86         [ x"$verbose" = x"-v -v" ] && msg "$*" >&3
87 }
88
89 # add initrd code to print to kmsg
90 # @param string message
91 # @param int loglevel. defaults to "6" (info)
92 # Log levels can be:
93 # Name          String  Meaning
94 # KERN_EMERG    "0"     Emergency messages, system is about to crash or is unstable
95 # KERN_ALERT    "1"     Something bad happened and action must be taken immediately
96 # KERN_CRIT     "2"     A critical condition occurred like a serious hardware/software failure
97 # KERN_ERR      "3"     An error condition, often used by drivers to indicate difficulties with the hardware
98 # KERN_WARNING  "4"     A warning, meaning nothing serious by itself but might indicate problems
99 # KERN_NOTICE   "5"     Nothing serious, but notably nevertheless. Often used to report security events.
100 # KERN_INFO     "6"     Informational message e.g. startup information at driver initialization
101 # KERN_DEBUG    "7"     Debug messages
102 # KERN_CONT     "c"     "continued" line of log printout (only done after a line that had no enclosing \n)
103 kmsg() {
104         local msg="$1" level=${2:-6}
105         echo "echo '<$level>$msg' > /dev/kmsg" | add_linuxrc
106 }
107
108 # aborts program abnormally
109 die() {
110         local rc=${2:-1}
111         msg "ERROR: $1" >&2
112         exit $rc
113 }
114
115 # find program from specified paths
116 find_tool() {
117         local x p b n
118         local paths="$initrd_dirs /bin /sbin /usr/bin /usr/sbin"
119         for x in "$@"; do
120                 debug "find_tool: checking $x"
121                 if [ -x "$x" ]; then
122                         echo $x
123                         verbose "find_tool: found $x"
124                         return 0
125                 fi
126                 n="$x"
127                 for p in $paths; do
128                         b=$(basename $x)
129                         debug "find_tool: checking $p/$b"
130                         if [ -x "$p/$b" ]; then
131                                 echo $p/$b
132                                 verbose "find_tool: found $p/$b"
133                                 return 0
134                         fi
135                         n="$n $p/$b"
136                 done
137         done
138         debug "find_tool: did not find any of: $n"
139         return 1
140 }
141
142 # loads geninitrd modules
143 geninitrd_load_mods() {
144         local mod
145         for mod in "$@"; do
146                 if [ ! -f /lib/geninitrd/mod-$mod.sh ]; then
147                         die "$mod geninitrd module can't be loaded"
148                 fi
149                 . /lib/geninitrd/mod-$mod.sh
150
151                 GENINITRD_MODS="$GENINITRD_MODS $mod"
152         done
153 }
154
155 # setup geninitrd modules
156 geninitrd_setup_mods() {
157         local mod
158
159         for mod in $GENINITRD_MODS; do
160                 debug "# $mod"
161
162                 # some mods want init
163                 if type setup_mod_$mod > /dev/null; then
164                         eval setup_mod_$mod
165                 fi
166         done
167 }
168
169 # append text to /linuxrc
170 # takes STDIN as input
171 add_linuxrc() {
172         cat >> "$RCFILE"
173 }
174
175 # generate code to mount /dev on tmpfs and create initial nodes
176 # can be called multiple times. /dev is cleaned up (umounted) automatically at
177 # the end of script.
178 mount_dev() {
179         # we already generated tmpfs code; return
180         if is_yes "$dev_mounted"; then
181                 return
182         fi
183
184         dev_mounted=yes
185
186         busybox_applet mount mknod mkdir
187         add_linuxrc <<-EOF
188                 : 'Creating /dev'
189                 if ! mount -t devtmpfs -o mode=0755,nosuid devtmpfs /dev > /dev/null 2>&1; then
190                         mount -o mode=0755,nosuid -t tmpfs tmpfs /dev
191                         mknod -m 600 /dev/console c 5 1
192                         mknod -m 666 /dev/null c 1 3
193                         mknod -m 666 /dev/zero c 1 5
194                         mknod -m 666 /dev/random c 1 8
195                         mknod -m 600 /dev/snapshot c 10 231
196                         mknod -m 666 /dev/urandom c 1 9
197                         mknod -m 666 /dev/ptmx c 5 2
198                         mknod -m 644 /dev/kmsg c 1 11
199                 fi
200                 mkdir /dev/pts
201                 mkdir /dev/shm
202         EOF
203 }
204
205 # load font
206 load_font() {
207         local font
208         [ ! -r /etc/sysconfig/console ] && return
209         . /etc/sysconfig/console
210         if [ -n "$CONSOLEFONT" ]; then
211                 font=$(ls -1 /lib/kbd/consolefonts/${CONSOLEFONT}*.gz 2> /dev/null)
212                 if [ -n "$font" ]; then
213                         verbose "Loading font $font"
214                         busybox_applet loadfont
215                         inst_d "/lib/kbd/consolefonts"
216                         cp -a "$font" "$DESTDIR/lib/kbd/consolefonts/"
217                         gunzip ${DESTDIR}/lib/kbd/consolefonts/${CONSOLEFONT}*.gz
218                         font=${font%.gz}
219                         echo "loadfont < $font" | add_linuxrc
220                 fi
221         fi
222 }
223
224 # generate code to mount /proc on initrd
225 # can be called multiple times
226 mount_proc() {
227         if is_yes "$proc_mounted"; then
228                 return
229         fi
230
231         proc_mounted=yes
232     if [ "$INITRDFS" = "initramfs" ]; then
233                 # /proc is mounted with initramfs 2.6.22.14 kernel
234                 # XXX: remove when it is clear why proc was already mounted
235                 echo "[ -f /proc/cmdline ] || mount -t proc none /proc" | add_linuxrc
236         else
237                 echo "mount -t proc none /proc" | add_linuxrc
238         fi
239 }
240
241 # generate code to mount /sys on initrd
242 # can be called multiple times
243 mount_sys() {
244         if is_yes "$sys_mounted"; then
245                 return
246         fi
247
248         sys_mounted=yes
249         echo "mount -t sysfs none /sys" | add_linuxrc
250 }
251
252 # generate code to mount /tmp on initrd
253 # can be called multiple times
254 mount_tmp() {
255     if [ "$INITRDFS" = "initramfs" ]; then
256                 # initramfs is read-write filesystem, no need for tmpfs
257                 return
258         fi
259
260         if is_yes "$tmp_mounted"; then
261                 return
262         fi
263
264         tmp_mounted=yes
265         echo "mount -t tmpfs none /tmp" | add_linuxrc
266 }
267
268 # generate code to mount /run on initrd
269 # can be called multiple times
270 mount_run() {
271         if is_yes "$run_mounted"; then
272                 return
273         fi
274
275         run_mounted=yes
276         echo "mount -t tmpfs run /run -o mode=0755,noexec,nosuid,nodev" | add_linuxrc
277 }
278
279 # unmount all mountpoints mounted by geninitrd
280 # try to move pseudo filesystems to newroot if possible
281 umount_all() {
282
283         add_linuxrc <<-'EOF'
284         : Last shell before umounting all and giving control over to real init.
285         debugshell
286         EOF
287
288         if is_yes "$run_mounted"; then
289                 add_linuxrc <<-EOF
290                 mount --bind /run /newroot/run
291                 umount /run
292                 EOF
293                 run_mounted=no
294         fi
295         if is_yes "$dev_mounted"; then
296                 add_linuxrc <<-EOF
297                 mount --bind /dev /newroot/dev
298                 umount /dev
299                 EOF
300                 dev_mounted=no
301         fi
302         if is_yes "$sys_mounted"; then
303                 add_linuxrc <<-EOF
304                 mount --bind /sys /newroot/sys
305                 umount /sys
306                 EOF
307                 sys_mounted=no
308         fi
309         if is_yes "$proc_mounted"; then
310                 add_linuxrc <<-EOF
311                 mount --bind /proc /newroot/proc
312                 umount /proc
313                 EOF
314                 proc_mounted=no
315         fi
316         if is_yes "$tmp_mounted"; then
317                 echo 'umount /tmp' | add_linuxrc
318                 tmp_mounted=no
319         fi
320 }
321
322 # Checks if busybox has support for APPLET(s)
323 # Exits from geninitrd if the support is not present.
324 #
325 # NB! XXX do not output to STDOUT, it will appear in initrd images in some cases!
326 busybox_applet() {
327         local err=0 applet
328
329         if [ -z "$busybox_functions" ]; then
330                 local tmp=$($busybox 2>&1)
331
332                 # BusyBox v1.1.3 says applet not found if it's not called 'busybox'.
333                 if [[ "$tmp" = *applet\ not\ found* ]]; then
334                         local t=$(mktemp -d)
335                         ln -s $busybox $t/busybox
336                         local tmp=$($t/busybox 2>&1)
337                         rm -rf $t
338                 fi
339
340                 busybox_functions=$(echo "$tmp" | \
341                         sed -ne '/Currently defined functions:/,$p' | \
342                         xargs | sed -e 's,.*Currently defined functions: ,,'
343                 )
344         fi
345         for applet in $*; do
346                 local have
347                 # try cache
348                 eval have='$'busybox_have_$applet
349                 if [ -z "$have" ]; then
350                         have=$(echo "$busybox_functions" | grep -Ec "( |^)$applet(,|$)")
351                         if [ "$have" = 0 ]; then
352                                 warn "This setup requires busybox-initrd compiled with applet '$applet' support"
353                                 err=1
354                         fi
355                         eval busybox_have_$applet=$have
356                 fi
357         done
358         if [ $err = 1 ]; then
359                 die "Aborted"
360         fi
361 }
362
363 # Extract the .config file from a kernel image
364 # uses extract-ikconfig from kernel sources (scripts/extract-ikconfig)
365 ikconfig() {
366         local kofile=$(modinfo -k $kernel -n configs 2> /dev/null)
367         if [ -n "$kofile" ]; then
368                 /lib/geninitrd/extract-ikconfig $kofile
369                 return
370         fi
371
372         # see if config available as separate file
373         if [ -f /boot/config-$kernel ]; then
374            cat /boot/config-$kernel
375            return
376         fi
377
378         # finally try vmlinuz itself
379         /lib/geninitrd/extract-ikconfig /boot/vmlinuz-$kernel
380 }
381
382 # @param    $module
383 basename_module() {
384         local module=$1
385
386         module=${module##*/}
387         module=${module%$modext*}
388         echo $module
389 }
390
391 # Finds module dependencies
392 #
393 # @param        $module
394 #
395 # Outputs full path to module and it's dependencies
396 find_depmod() {
397         local module="$1"
398         local skiperrors=0
399
400         # if module is prefixed with dash, we should ignore errors if the module
401         # can't be found.
402         if [ ${module#-} != $module ]; then
403                 skiperrors=1
404                 module=${module#-}
405         fi
406
407         # This works when user has module-init-tools installed even on 2.4 kernels
408         local modprobe
409         modprobe=$(modprobe --set-version $kernel --show-depends $module --ignore-install 2>&1)
410
411         if [ $? != 0 ]; then
412                 if [ $skiperrors = 1 ]; then
413                         return 0
414                 fi
415                 echo >&2 "$modprobe"
416
417                 if ! is_no "$EXIT_IF_MISSING"; then
418                         die "$module: module not found for $kernel kernel"
419                 fi
420
421                 warn "$module: module not found for $kernel kernel"
422                 warn "If $module isn't compiled in kernel then this initrd may not start your system."
423         fi
424
425         local smodule
426
427         echo "$modprobe" | \
428         while read insmod modpath options; do
429                 if [ "$insmod" = "insmod" ]; then
430
431                         # XXX: find a away to autodetect
432                         smodule=$(basename_module $modpath)
433                         case "$smodule" in
434                                 btrfs)
435                                         find_depmod "-libcrc32c"
436                                         ;;
437                                 crc-t10dif)
438                                         find_depmod "-crct10dif-pclmul"
439                                         find_depmod "-crct10dif"
440                                         ;;
441                                 libcrc32c)
442                                         find_depmod "-crc32c-intel"
443                                         find_depmod "-crc32c"
444                                         ;;
445                                 virtio_blk|virtio_scsi)
446                                         find_depmod "-virtio_pci"
447                                         find_depmod "-virtio_mmio"
448                                         ;;
449                         esac
450
451                         echo $modpath
452                 fi
453         done
454         return 0
455 }
456
457 find_firmware() {
458         local module="$1"
459
460         # no firmware support in 2.4 kernels
461         if [ "$kernel_version_long" -lt "002005048" ]; then
462                 return
463         fi
464         echo -n $(NEW_MODINFO=1 modinfo -k $kernel -F firmware $module 2>/dev/null | xargs)
465 }
466
467 # @param        $module
468 find_module() {
469         local mod depmod module=$1
470
471         depmod=$(find_depmod $module) || exit 1
472         for mod in $depmod; do
473                 mod=${mod#/lib/modules/$kernel/}
474
475                 # add each module only once
476                 local m have=0
477                 for m in $MODULES; do
478                         [ $m = $mod ] && have=1
479                 done
480                 if [ $have = 0 ]; then
481                         MODULES="$MODULES $mod"
482                 fi
483         done
484 }
485
486 # install a file to temporary mount image.
487 # it will operate recursively (copying directories)
488 # and will symlink destinations if source is symlink.
489 inst() {
490         if [ $# -lt 2 ]; then
491                 die 'Usage: inst <file> [<file>] <destination>'
492         fi
493
494         local src i=0 c=$(($# - 1))
495         while [ $i -lt $c ]; do
496                 src="$src $1"
497                 i=$((i + 1))
498                 shift
499         done
500         local dest=$1
501         set -- $src
502         local parentDir=$(dirname $DESTDIR$dest)
503         if [ ! -d "$parentDir" ]; then
504                 verbose "+ mkdir -p DESTDIR${parentDir#$DESTDIR}"
505                 mkdir -p $parentDir
506         fi
507         verbose "+ cp $* DESTDIR$dest"
508         cp -HRp "$@" "$DESTDIR$dest"
509 }
510
511 inst_d() {
512         if [ $# = 0 ]; then
513                 die 'Usage: inst_d <destination> <destination>'
514         fi
515         local dir
516         for dir in "$@"; do
517                 install -d "$DESTDIR$dir"
518         done
519 }
520
521 # install executable and it's shared libraries
522 inst_exec() {
523         if [ $# -lt 2 ]; then
524                 die "Invalid params ($@), Usage: inst_exec <file>[, <file>] <destination>"
525         fi
526         local src i=0 c=$(($# - 1))
527         while [ $i -lt $c ]; do
528                 src="$src $1"
529                 i=$((i + 1))
530                 shift
531         done
532         local dest=$1
533         set -- $src
534
535         inst "$@" $dest
536
537         local obj lib libs libdir
538         for obj in "$@"; do
539                 case "$obj" in
540                         /lib/ld-linux.so.2 | /lib64/ld-linux-x86-64.so.2 | /libx32/ld-linux-x32.so.2)
541                         continue
542                 esac
543
544                 libs=$(ldd "$obj" | awk '/statically|linux-(gate|vdso)\.so/{next} NF == 2 {print $1} /=/{print $3}' | sort -u)
545                 for lib in $libs; do
546                         libdir=$(cd $(dirname "$lib"); pwd)
547                         if [ ! -f "$DESTDIR/$lib" ]; then
548                                 inst_d $libdir
549                                 inst_exec $lib $libdir
550                         fi
551                 done
552         done
553
554         # hack for uclibc linked binaries requiring this fixed path
555         # XXX: shouldn't rpath be used here instead so th
556         for _lib in $(get_libdir LIBDIR); do
557                 if [ -f $DESTDIR/$_lib/libc.so.0 ]; then
558                         lib=$DESTDIR/$_lib/libc.so.0
559                         lib=$(ldd "$lib" | awk '/statically|linux-(gate|vdso)\.so/{next} NF == 2 {print $1} /=/{print $3}' | sort -u)
560                         libdir=$(cd $(dirname "$lib"); pwd)
561                         if [ ! -e $DESTDIR$libdir ]; then
562                                 libdir=$(dirname "$libdir")
563                                 inst_d $libdir
564                                 verbose "+ ln -s /$_lib $DESTDIR$libdir"
565                                 ln -s /$_lib $DESTDIR$libdir
566                                 break
567                         fi
568                 fi
569         done
570 }
571
572 # output modules.conf / modprobe.conf
573 modprobe_conf() {
574         echo "$modprobe_conf_cache"
575 }
576
577 # return options for MODULE
578 # @param $1 module name
579 modprobe_options() {
580         local module=$1
581         local options=$(modprobe_conf | awk -vmodule="$module" '{ if ($1 == "options" && $2 == module) { for(i=3;i<=NF;i++) printf("%s ",$i); }}')
582         echo ${options# }
583 }
584
585 #
586 # defaults to modprobe -c if not told otherwise, this means include statements
587 # work from there.
588 cache_modprobe_conf() {
589         if [ "$kernel_version" -lt "002005" ]; then
590                 modulefile=/etc/modules.conf
591                 if [ ! -f "$modulefile" -a -f /etc/conf.modules ]; then
592                         modulefile=/etc/conf.modules
593                 fi
594         fi
595
596         if [ -n "$modulefile" ]; then
597                 debug "Using $modulefile for modules config"
598                 modprobe_conf_cache=$(cat $modulefile | awk '!/^[\t ]*#/ { print }')
599
600         else
601                 debug "Using modprobe -c to get modules config"
602                 modprobe_conf_cache=$(modprobe -c --set-version $kernel | awk '!/^[\t ]*#/ { print }')
603         fi
604 }
605
606 # find modules for $devpath
607 find_modules_for_devpath() {
608         local devpath="$1"
609         if [ -z "$devpath" ]; then
610                 die "No argument passed to find_modules_for_devpath() - is your /etc/fstab correct?"
611         fi
612
613         if [[ "$devpath" = /dev/dm-* ]]; then
614                 # /dev/dm-3 -> /dev/mapper/sil_ahbgadcbchfc3
615                 devpath=$(dm_node "$devpath")
616         fi
617
618         if [ -L "$devpath" ] && ! is_lvm "$devpath" && ! is_luks "$devpath"; then
619                 # sanitize things like:
620                 # /dev/block/104:2 -> /dev/cciss/c0d0p2
621                 devpath=$(readlink -f "$devpath")
622         fi
623
624         verbose "Finding modules for device path $devpath"
625
626         if is_luks "$devpath"; then
627                 find_modules_luks "$devpath"
628                 return
629         fi
630
631         if is_nfs "$devpath"; then
632                 find_modules_nfs "$devpath"
633                 return
634         fi
635
636         if is_md "$devpath"; then
637                 find_modules_md "$devpath"
638                 return
639         fi
640
641         if is_multipath "$devpath"; then
642                 if find_modules_multipath "$devpath"; then
643                         return
644                 fi
645
646                 # fallback
647         fi
648
649         if is_dmraid "$devpath"; then
650                 if find_modules_dmraid "$devpath"; then
651                         return
652                 fi
653                 # fallback
654         fi
655
656         if is_scsi "$devpath"; then
657                 find_modules_scsi "$devpath"
658                 return
659         fi
660
661         if is_ide "$devpath"; then
662                 find_modules_ide "$devpath"
663                 return
664         fi
665
666         if [[ "$devpath" == /dev/bcache* ]]; then
667                 find_modules_bcache "$devpath"
668                 return
669         fi
670
671         if [[ "$devpath" == /dev/rd/* ]]; then
672                 find_module "DAC960"
673                 rootdev_add=/dev/rd/
674                 return
675         fi
676
677         if [[ "$devpath" == /dev/ida/* ]]; then
678                 find_module "cpqarray"
679                 rootdev_add=/dev/ida/
680                 return
681         fi
682
683         if [[ "$devpath" == /dev/cciss/* ]]; then
684                 rootdev_add=/dev/cciss/
685
686                 # load hpsa for future kernels, cciss for backwards compat
687                 if [ "$kernel_version_long" -ge "003000000" ]; then
688                         find_module "hpsa" "-cciss"
689                         find_modules_scsi "$devpath"
690                 else
691                         find_module "cciss"
692                 fi
693
694                 return
695         fi
696
697         if [[ "$devpath" == /dev/ataraid/* ]]; then
698                 find_modules_ide
699                 find_module "ataraid"
700                 ataraidmodules=$(modprobe_conf | awk '/ataraid_hostadapter/ { print $3 }')
701                 if [ -n "$ataraidmodules" ]; then
702                         # FIXME: think about modules compiled in kernel
703                         die "ataraid_hostadapter alias not defined in modprobe.conf! Please set it and run $PROGRAM again."
704                 fi
705                 for n in $ataraidmodules; do
706                         find_module "$n"
707                 done
708                 rootdev_add=/dev/ataraid/
709                 return
710         fi
711
712         # check to see if we need to set up a loopback filesystem
713         if [[ "$devpath" == /dev/loop*  ]]; then
714                 die "Sorry, root on loop device isn't supported."
715                 # TODO: rewrite for bsp and make nfs ready
716                 if [ ! -x /sbin/losetup ]; then
717                         die "losetup is missing"
718                 fi
719                 key="^# $(echo $devpath | awk -F/ '{print($3);}' | tr '[a-z]' '[A-Z]'):"
720                 if ! is_yes "`awk '/'$key'/ { print( "yes"); }' $fstab`"; then
721                         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"
722                 fi
723
724                 line="`awk '/'$key'/ { print $0; }' $fstab`"
725                 loopDev="$(echo $line | awk '{print $3}')"
726                 loopFs="$(echo $line | awk '{print $4}')"
727                 loopFile="$(echo $line | awk '{print $5}')"
728
729                 BASICMODULES="$BASICMODULES -loop"
730                 find_module "-$loopFs"
731                 BASICMODULES="$BASICMODULES -${loopFs}"
732                 return
733         fi
734
735         if is_lvm "$devpath"; then
736                 find_modules_lvm "$devpath"
737                 return
738         fi
739 }
740
741 firmware_install_module() {
742         local module="$1"
743         local firmware_files="$2"
744
745         verbose "Adding Firmwares ($firmware_files) to initrd for module $module"
746         # firmware not yet installed
747         if [ ! -f "$DESTDIR/lib/firmware/firmware.sh" ]; then
748                 inst_d /lib/firmware
749 cat << 'EOF' >> "$DESTDIR/lib/firmware/firmware.sh"
750 #!/bin/sh -e
751 # handle only firmware add requests
752 if [ "$SUBSYSTEM" != "firmware" ]; then
753         exit 0
754 fi
755 if [ "$ACTION" != "add" ]; then
756         exit 0
757 fi
758 echo 1 > /sys$DEVPATH/loading
759 cat "/lib/firmware/$FIRMWARE" > /sys$DEVPATH/data
760 echo 0 > /sys$DEVPATH/loading
761 exit 0
762 EOF
763                 chmod 755 "$DESTDIR/lib/firmware/firmware.sh"
764
765                 # setup firmware loader agent
766                 echo "echo -n "/lib/firmware/firmware.sh" > /proc/sys/kernel/hotplug" | add_linuxrc
767         fi
768
769         for firmware in $firmware_files; do
770                 if [ -f "/lib/firmware/$kernel/$firmware" ]; then
771                         FIRMWAREDIR=${firmware%/*}
772                         [ "$FIRMWAREDIR" != "$firmware" ] && inst_d /lib/firmware/$FIRMWAREDIR
773                         inst /lib/firmware/$kernel/$firmware /lib/firmware/$firmware
774                 elif [ -f "/lib/firmware/$firmware" ]; then
775                         FIRMWAREDIR=${firmware%/*}
776                         [ "$FIRMWAREDIR" != "$firmware" ] && inst_d /lib/firmware/$FIRMWAREDIR
777                         inst /lib/firmware/$firmware /lib/firmware/$firmware
778                 else
779                         warn "Possible missing firmware file /lib/firmware/$firmware or /lib/firmware/$kernel/$firmware for module $module."
780                 fi
781         done
782
783         mount_sys
784 }
785
786 modules_install() {
787         local modules="$1"
788         local mod
789
790         for mod in $modules; do
791                 MODULEDIR=${mod%/*}
792                 inst_d "/lib/modules/$kernel/$MODULEDIR"
793                 cp -a "/lib/modules/$kernel/$mod" "$DESTDIR/lib/modules/$kernel/$mod"
794                 case $mod in
795                         *.gz)
796                                 gunzip "$DESTDIR/lib/modules/$kernel/$mod" || die "Can't uncompress gz"
797                                 mod=${mod%.gz}
798                                 ;;
799                         *.xz)
800                                 xz -d "$DESTDIR/lib/modules/$kernel/$mod" || die "Can't uncompress xz"
801                                 mod=${mod%.xz}
802                                 ;;
803                         *.bz2)
804                                 bzip2 -d "$DESTDIR/lib/modules/$kernel/$mod" || die "Can't uncompress bz2"
805                                 mod=${mod%.bz2}
806                                 ;;
807                 esac
808                 if [ "$STRIP" ] && [ -x "$STRIP" ]; then
809                         $STRIP -g --remove-section=.comment "$DESTDIR/lib/modules/$kernel/${mod}"
810                 fi
811         done
812 }
813
814 modules_add_linuxrc() {
815         local mod modpath
816
817         for mod in "$@"; do
818                 # module path without optional compression
819                 modpath=${mod%.gz}
820                 modpath=${modpath%.xz}
821                 modpath=${modpath%.bz2}
822
823                 # name of the module
824                 local module=${modpath##*/}; module=${module%$modext}
825                 local options=$(modprobe_options "$module")
826                 local genericname=$(echo $module | tr - _)
827                 local usleep=$(eval echo \$MODULE_${genericname}_USLEEP)
828                 local firmware=$(eval echo \$MODULE_${genericname}_FIRMWARE)
829
830                 if [ "$module" = "scsi_mod" -a "$kernel_version_long" -ge "002006030" ]; then
831                         options="scan=sync $options"
832                 fi
833
834                 if [ x"$verbose" = x"-v" ]; then
835                         s=""
836                         if [ "$options" ]; then
837                                 s="$s with options [$options]"
838                         fi
839                         if [ "$usleep" ]; then
840                                 s="$s and $usleep usleep"
841                         fi
842                         verbose "Loading module [$module]$s"
843                 fi
844
845                 if [ -n "$firmware" ]; then
846                         firmware_install_module "$module" "$firmware"
847                 else
848                         for file in $(find_firmware "$module"); do
849                                 firmware_install_module "$module" "$file"
850                         done
851                 fi
852
853                 echo "insmod /lib/modules/$kernel/$modpath $options" | add_linuxrc
854                 if [ -n "$usleep" ]; then
855                         echo "usleep $usleep" | add_linuxrc
856                 fi
857                 if [ "$module" = "scsi_wait_scan" ]; then
858                         if [ "$(busybox_applet rmmod 2>/dev/null; echo $?)" = 0 ]; then
859                                 echo "rmmod scsi_wait_scan" | add_linuxrc
860                         fi
861                 fi
862
863         done
864 }
865
866 # Generates /dev nodes based on /proc/partitions information.
867 # Needs /proc mounted.
868 # Can be called multiple times.
869 initrd_gen_devices() {
870         if is_yes "$proc_partitions"; then
871                 return
872         fi
873         proc_partitions=yes
874
875         mount_dev
876         add_linuxrc <<-'EOF'
877                 : 'Making device nodes'
878                 cat /proc/partitions | (
879                         # ignore first two lines: header, empty line
880                         read b; read b
881
882                         while read major minor blocks dev rest; do
883                                 node=/dev/$dev
884                                 mkdir -p ${node%/*}
885                                 [ -e $node ] || mknod -m 660 $node b $major $minor
886                         done
887                 )
888         EOF
889 }
890
891
892 initrd_gen_setrootdev() {
893         verbose "Adding rootfs finding based on kernel cmdline root= option support."
894         busybox_applet ls
895         debug "Current /proc/partitions:\n$(sed -e 's,^,| ,' /proc/partitions)"
896         add_linuxrc <<-'EOF'
897                 if [ "${ROOT##/dev/}" != "${ROOT}" ]; then
898                         rootnr="$(busybox awk -v rootnode="${ROOT##/dev/}" '$4 == rootnode { print 256 * $1 + $2 }' /proc/partitions)"
899                         # fallback to ls, try two different formats
900                         # http://lists.pld-linux.org/mailman/pipermail/pld-devel-en/2014-May/023915.html
901                         if [ "${rootnr:-0}" = 0 -a -e "$ROOT" ]; then
902                                 # busybox up to 1.22
903                                 rootnr="$(busybox ls -lL ${ROOT} | busybox awk '{if (/^b/) { print 256 * $3 + $4; }}')"
904                         fi
905                         if [ "${rootnr:-0}" = 0 -a -e "$ROOT" ]; then
906                                 # busybox 1.22 and upwards
907                                 rootnr="$(busybox ls -lL ${ROOT} | busybox awk '{if (/^b/) { print 256 * $5 + $6; }}')"
908                         fi
909                         if [ "${rootnr:-0}" -gt 0 ]; then
910                                 echo "$rootnr" > /proc/sys/kernel/real-root-dev
911                         fi
912                 fi
913         EOF
914 }
915
916 initrd_gen_initramfs_switchroot() {
917         inst_d /newroot
918         if [ "$rootdev" = "/dev/nfs" ]; then
919                 echo "rootfs on NFS root=/dev/nfs"
920         else
921                 [ ! -e "$DESTDIR/$rootdev" ] && inst $rootdev $rootdev
922         fi
923
924         # parse 'root=xxx' kernel commandline
925         # We support passing root as hda3 /dev/hda3 0303 0x0303 and 303
926
927         # from lilo-23.2/readme/README:
928         # root=<device> changes the root device. This overrides settings that may
929         # have been made in the boot image and on the LILO command line. <device> is
930         # either the hexadecimal device number or the full path name of the device,
931         # e.g. /dev/hda3 [*]
932         #
933         #  *  The device names are hard-coded in the kernel. Therefore, only the
934         #         "standard" names are supported and some less common devices may not be
935         #         recognized. In those cases, only numbers can be used.
936         busybox_applet cat
937         add_linuxrc <<-'EOF'
938                 device=
939                 eval "$(busybox awk -v root="$ROOT" '
940                         # http://9fans.net/archive/2006/09/261
941                         function h2d(str, hstr, res, num, n, digit, i) {
942                                 hstr = "0123456789abdcef";
943                                 res = 0;
944                                 n = split(tolower(str), digit, "");
945
946                                 for (i = 1; i <= n; i++) {
947                                         num = index(hstr, digit[i]) - 1;
948                                         res = res + (num * 16 ^ (n - i));
949                                 }
950
951                                 return res;
952                         }
953                         BEGIN {
954
955                                 num_pattern_short = "[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]";
956                                 num_pattern = "[0-9a-fA-F]" num_pattern_short;
957                                 dev_pattern = "[hms][a-z][a-z]([0-9])+";
958                                 partition = "";
959                                 min = -1; maj = -1;
960
961                                 # see if we have /dev/hdX or hdX, we can just take partition name
962                                 if (root ~ "^\/dev\/" dev_pattern "$" || root ~ "^" dev_pattern "$") {
963                                         partition = root
964                                         sub("^/dev/", "", partition);
965
966                                 } else {
967                                         # unify values first
968                                         if (root ~ "^" num_pattern_short "$")  {
969                                                 # change "303" => "0x0303"
970                                                 root = "0x0" root
971                                         } else if (root ~ "^" num_pattern "$")  {
972                                                 # change "0303" => "0x0303"
973                                                 root = "0x" root
974                                         }
975
976                                         maj = h2d(substr(root, 3, 2));
977                                         min = h2d(substr(root, 5, 2));
978                                 }
979                         }
980
981                         partition && $4 == partition { maj = $1; min = $2; }
982                         $1 == maj && $2 == min { partition = $4; }
983
984                         END {
985                                 if (maj >= 0 && min >= 0) {
986                                         printf("maj=%s; min=%s;\n", maj, min);
987                                 }
988                                 if (partition) {
989                                         printf("device=/dev/%s;\n", partition);
990                                 }
991                         }
992                         ' /proc/partitions)"
993
994                 if [ -z "$device" ]; then
995                         if [ "$DEBUGINITRD" ]; then
996                                 cat /proc/partitions
997                         fi
998                         device=$ROOT
999                 fi
1000
1001                 if [ "$device" -a ! -b $device -a "$maj$min" ]; then
1002                         mknod -m 660 $device b $maj $min
1003                 fi
1004
1005                 # XXX hack, fallback to rootdev from geninitrd time
1006                 if [ ! -e "$device" ]; then
1007         EOF
1008         add_linuxrc <<-EOF
1009                         device="$rootdev"
1010         EOF
1011         add_linuxrc <<-'EOF'
1012                         echo "DEVICE set to $device based on fstab entry from initrd gen time"
1013                 fi
1014
1015                 # XXX hack, if no device, try to parse it from /proc/partitions using /proc/sys/kernel/real-root-dev
1016                 if [ ! -e "$device" ]; then
1017                         rrd=$(cat /proc/sys/kernel/real-root-dev)
1018                         major=$(($rrd / 256))
1019                         minor=$(($rrd % 256))
1020
1021                         while read pmajor pminor blocks dev rest; do
1022                                 # skip header and empty line
1023                                 [ -z "$pmajor" -o "$pmajor" = "major" ] && continue
1024
1025                                 if [ $pmajor = $major -a $pminor = $minor ]; then
1026                                         device=/dev/$dev
1027                                         echo "DEVICE set to $device based on real-root-dev"
1028                                 fi
1029                         done < /proc/partitions
1030                 fi
1031
1032                 [ -n "$ROOTFLAGS" ] && ROOTFLAGS="-o $ROOTFLAGS"
1033
1034                 mount -t $ROOTFS -r $device $ROOTFLAGS /newroot || echo "Mount of rootfs failed."
1035                 init=$INIT
1036                 if [ -z "$init" -o ! -x "/newroot$init" ]; then
1037                         init=/sbin/init
1038                 fi
1039         EOF
1040
1041         busybox_applet dmesg
1042         busybox_applet tail
1043         add_linuxrc <<-'EOF'
1044                 if [ "$DEBUGINITRD" ]; then
1045                         echo "Last 20 lines of dmesg:"
1046                         dmesg | tail -n 20
1047                 fi
1048
1049         EOF
1050
1051         kmsg "geninitrd/$VERSION switching root"
1052
1053         umount_all
1054         busybox_applet switch_root usleep
1055         add_linuxrc <<-'EOF'
1056                 [ ! -e /newroot/dev/console ] && mknod -m 660 /newroot/dev/console c 5 1
1057
1058                 # switch root to empty dir will make kernel panic, so sleep 10s before it
1059                 # switch_root needs to be pid 1, so there's no other way to recover from here
1060                 # if /dev is missing, switch root will likely fail, give debug shell before that
1061                 if [ ! -d /newroot/dev ]; then
1062                         echo "/dev is missing, switch_root will likely fail"
1063                         echo "if you booted with debugrd=sh, then you be given shell and you might able to recover this situation"
1064                         debugshell
1065                         [ "$DEBUGINITRD" ] || usleep 10000000
1066                 fi
1067
1068                 # systemd[1]: /usr appears to be on its own filesytem and is not
1069                 # already mounted. This is not a supported setup. Some things will
1070                 # probably break (sometimes even silently) in mysterious ways. Consult
1071                 # http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken
1072                 # for more information.
1073                 echo trying to mount /usr
1074                 chroot /newroot mount -n /usr
1075
1076                 exec switch_root /newroot $init ${1:+"$@"}
1077
1078                 # FIXME: this code is never executed, as "exec" does not return!
1079
1080                 echo "Error! initramfs should not reach this place."
1081                 echo "It probably means you've got old version of busybox, with broken"
1082                 echo "initramfs support. Trying to boot anyway, but won't promise anything."
1083
1084                 exec chroot /newroot $init ${1:+"$@"}
1085
1086                 echo "Failed to chroot!"
1087                 debugshell
1088         EOF
1089         # we need /init being real file, not symlink, otherwise the initramfs will
1090         # not be ran by pid 1 which is required for switch_root
1091         mv $DESTDIR/linuxrc $DESTDIR/init
1092         ln -s init $DESTDIR/linuxrc
1093 }
1094
1095 # find if $symbol exists in System.map $mapfile
1096 sym_exists() {
1097         local mapfile="$1"
1098         local symbol="$2"
1099         if [ ! -f $mapfile ]; then
1100                 # missing mapfile (not a pld kernel?)
1101                 return 1
1102         fi
1103
1104         awk -vc=1 -vsymbol="$symbol" '($2 == "T" || $2 == "t") && $3 == symbol {c = 0} END {exit c}' $mapfile
1105 }
1106
1107 # find best compressor (or forced one) for initrd
1108 find_compressor() {
1109         local mode="$1"
1110         local compressors='xz lzma bzip2 gzip lzo'
1111
1112         # a specified one, take it
1113         if ! is_yes "$mode"; then
1114                 compressors="$mode"
1115         fi
1116
1117         verbose "finding compressor: $compressors (via $mode)"
1118         # check for compressor validity
1119         local c prog map=/boot/System.map-$kernel
1120         for c in $compressors; do
1121                 case $c in
1122                 xz)
1123                         sym=unxz
1124                         prog=/usr/bin/xz
1125                         ;;
1126                 lzma)
1127                         sym=unlzma
1128                         prog=/usr/bin/xz
1129                         ;;
1130                 bzip2)
1131                         sym=bzip2
1132                         prog=/usr/bin/bzip2
1133                         ;;
1134                 gzip)
1135                         sym=gunzip
1136                         prog=/bin/gzip
1137                         ;;
1138                 lzo)
1139                         sym=unlzo
1140                         prog=/usr/bin/lzop
1141                         ;;
1142                 none|no)
1143                         # any existing sym will work
1144                         sym=initrd_load
1145                         prog=/bin/cat
1146                         ;;
1147                 *)
1148                         die "Unknown compressor $c"
1149                         ;;
1150                 esac
1151                 if sym_exists $map $sym && [ -x $prog ]; then
1152                         echo $c
1153                         return
1154                 fi
1155         done
1156
1157         verbose "using gzip for compressor (fallback)"
1158         echo gzip
1159 }
1160
1161 # compresses kernel image image
1162 # in function so we could retry with other compressor on failure
1163 compress_image() {
1164         local compressor="$1" IMAGE="$2" target="$3" tmp
1165         tmp=$(mktemp "$target".XXXXXX) || die "mktemp failed"
1166
1167         case "$compressor" in
1168         xz)
1169                 # don't use -9 here since kernel won't understand it
1170                 xz --format=xz --check=crc32 --lzma2=preset=6e,dict=1MiB < "$IMAGE" > "$tmp" || return $?
1171                 ;;
1172         lzma)
1173                 xz --format=lzma -9 < "$IMAGE" > "$tmp" || return $?
1174                 ;;
1175         bzip2)
1176                 bzip2 -9 < "$IMAGE" > "$tmp" || return $?
1177                 ;;
1178         gzip)
1179                 gzip -9 < "$IMAGE" > "$tmp" || return $?
1180                 ;;
1181         lzo)
1182                 lzop -9 < "$IMAGE" > "$tmp" || return $?
1183                 ;;
1184         none|no)
1185                 cat < "$IMAGE" > "$tmp" || return $?
1186                 ;;
1187         esac
1188
1189         mv -f "$tmp" "$target"
1190 }
1191
1192 if [ -r /etc/sysconfig/geninitrd ]; then
1193         . /etc/sysconfig/geninitrd
1194 fi
1195
1196 if [ ! -f /proc/mounts ]; then
1197         warn "/proc filesystem not mounted, may cause wrong results or failure."
1198 fi
1199
1200 geninitrd_load_mods ide luks multipath dmraid lvm md blkid udev tuxonice suspend fbsplash condecor bootsplash uvesafb nfs sata scsi usbkbd bcache
1201
1202 while [ $# -gt 0 ]; do
1203         case $1 in
1204         --fstab=*)
1205                 fstab=${1#--fstab=}
1206                 ;;
1207         --fstab)
1208                 fstab=$2
1209                 shift
1210                 ;;
1211         --modules-conf=*)
1212                 modulefile=${1#--modules-conf=}
1213                 ;;
1214         --modules-conf)
1215                 modulefile=$2
1216                 shift
1217                 ;;
1218         --with-bootsplash)
1219                 BOOT_SPLASH=yes
1220                 ;;
1221         --without-bootsplash)
1222                 BOOT_SPLASH=no
1223                 ;;
1224         --with-fbsplash)
1225                 FB_SPLASH=yes
1226                 ;;
1227         --without-fbsplash)
1228                 FB_SPLASH=no
1229                 ;;
1230         --with-fbcondecor)
1231                 FB_CON_DECOR=yes
1232                 ;;
1233         --without-fbcondecor)
1234                 FB_CON_DECOR=no
1235                 ;;
1236         --with-suspend)
1237                 USE_SUSPEND=yes
1238                 ;;
1239         --without-suspend)
1240                 USE_SUSPEND=no
1241                 ;;
1242         --with-suspend2 | --with-tuxonice)
1243                 USE_TUXONICE=yes
1244                 ;;
1245         --without-suspend2 | --without-tuxonice)
1246                 USE_TUXONICE=no
1247                 ;;
1248         --lvmversion=*)
1249                 LVMTOOLSVERSION=${1#--lvmversion=}
1250                 ;;
1251         --lvmtoolsversion=*)
1252                 LVMTOOLSVERSION=${1#--lvmtoolsversion=}
1253                 ;;
1254         --lvmtoolsversion|--lvmversion)
1255                 LVMTOOLSVERSION=$2
1256                 shift
1257                 ;;
1258         --without-udev)
1259                 USE_UDEV=no
1260                 ;;
1261         --with-udev)
1262                 USE_UDEV=yes
1263                 ;;
1264         --without-dmraid)
1265                 USE_DMRAID=no
1266                 ;;
1267         --without-multipath)
1268                 USE_MULTIPATH=no
1269                 ;;
1270         --with-multipath=*)
1271                 USE_MULTIPATH=${1#--with-multipath=}
1272                 ;;
1273         --without-blkid)
1274                 USE_BLKID=no
1275                 ;;
1276         --without-luks)
1277                 USE_LUKS=no
1278                 ;;
1279         --with=*)
1280                 BASICMODULES="$BASICMODULES ${1#--with=}"
1281                 ;;
1282         --with)
1283                 BASICMODULES="$BASICMODULES $2"
1284                 shift
1285                 ;;
1286         --version)
1287                 echo "$PROGRAM: version $VERSION"
1288                 exit 0
1289                 ;;
1290         -v)
1291                 if [ x"$verbose" = x"-v" ]; then
1292                         verbose="-v -v"
1293                 else
1294                         verbose="-v"
1295                 fi
1296                 exec 3>&1
1297                 ;;
1298         --compress)
1299                 COMPRESS=$2
1300                 ;;
1301         --compress=*)
1302                 COMPRESS="${1#--compress=}"
1303                 ;;
1304         --nocompress)
1305                 COMPRESS=no
1306                 ;;
1307         --nostrip)
1308                 STRIP=
1309                 ;;
1310         --strip=*)
1311                 STRIP="${1#--strip=}"
1312                 ;;
1313         --strip)
1314                 STRIP=$2
1315                 shift
1316                 ;;
1317         --ifneeded)
1318                 ifneeded=1
1319                 ;;
1320         -f)
1321                 force=1
1322                 ;;
1323         --preload=*)
1324                 PREMODS="$PREMODS ${1#--preload=}"
1325                 ;;
1326         --preload)
1327                 PREMODS="$PREMODS $2"
1328                 shift
1329                 ;;
1330         --fs=* | --fs)
1331                 die "--fs option is obsoleted. Use --initrdfs instead"
1332                 ;;
1333         --initrdfs=*)
1334                 INITRDFS=${1#--initrdfs=}
1335                 ;;
1336         --initrdfs)
1337                 INITRDFS=$2
1338                 shift
1339                 ;;
1340         --image-version)
1341                 img_vers=yes
1342                 ;;
1343         --ide-only-root)
1344                 ide_only_root="yes"
1345                 ;;
1346         *)
1347                 if [ -z "$target" ]; then
1348                         target="$1"
1349                 elif [ -z "$kernel" ]; then
1350                         kernel="$1"
1351                 else
1352                         usage
1353                         exit 1
1354                 fi
1355                 ;;
1356         esac
1357
1358         shift
1359 done
1360
1361 if [ -z "$target" -o -z "$kernel" ]; then
1362         usage
1363         exit 1
1364 fi
1365
1366 # main()
1367 if [ "$(id -u)" != 0 ]; then
1368         die "You need to be root to generate initrd"
1369 fi
1370
1371 for dir in libx32 lib64 lib; do
1372         initrd_dir=/usr/$dir/initrd
1373         if [ -d "$initrd_dir" ]; then
1374                 initrd_dirs="$initrd_dirs $initrd_dir"
1375         fi
1376 done
1377
1378 kernel_version=$(echo "$kernel" | awk -F. '{gsub(/[_-].*/, "", $0); print sprintf("%03d%03d",$1,$2)}')
1379 kernel_version_long=$(echo "$kernel" | awk -F. '{gsub(/[_-].*/, "", $0); print sprintf("%03d%03d%03d",$1,$2,$3)}')
1380
1381 verbose "# geninitrd $VERSION"
1382 debug "Using initrd_dir: $initrd_dir"
1383
1384 busybox=$(find_tool $initrd_dir/busybox $initrd_dir/initrd-busybox /bin/initrd-busybox) || die "Couldn't find busybox suitable for initrd"
1385
1386 # we setup mods after parsing command line args
1387 geninitrd_setup_mods
1388
1389 if [ ! -f /boot/vmlinuz-"$kernel" ]; then
1390         warn "/boot/vmlinuz-$kernel doesn't exist, is your /boot mounted?"
1391 fi
1392
1393 if [ -z "$INITRDFS" ]; then
1394         if [ -n "$FS" ]; then
1395                 # FS= can came only via /etc/sysconfig/geninitrd likely?
1396                 die "FS configuration option is obsoleted. Use INITRDFS instead"
1397         fi
1398
1399         # default value
1400         if [ "$kernel_version" -ge "002005" ]; then
1401                 INITRDFS="initramfs"
1402         else
1403                 INITRDFS="rom"
1404         fi
1405 fi
1406
1407 check_initrd_fs() {
1408         local s sfound sym p prog map=/boot/System.map-$kernel
1409         case "$INITRDFS" in
1410                 ext2)
1411                         # TODO: symbols to check in case of ext2 used via ext3/4 subsystem
1412                         sym=init_ext2_fs
1413                         prog=/sbin/mke2fs
1414                         ;;
1415                 rom|romfs)
1416                         sym=init_romfs_fs
1417                         prog=/sbin/genromfs
1418                         ;;
1419                 cram|cramfs)
1420                         sym=init_cramfs_fs
1421                         prog=/sbin/mkcramfs
1422                         ;;
1423                 initramfs)
1424                         sym=__initramfs_start
1425                         prog="/bin/cpio /usr/bin/find"
1426                         ;;
1427                 *)
1428                         die "Filesystem $INITRDFS on initrd is not supported by geninitrd"
1429                         ;;
1430         esac
1431
1432         # only one is needed (for cases like ext2 via ext2 or via ext3 or via ext4 subsysytem)
1433         sfound=0
1434         for s in $sym; do
1435                 sym_exists $map $s && sfound=1
1436                 break
1437         done
1438         if [ "$sfound" -eq "0" ]; then
1439                 die "Filesystem $INITRDFS on initrd is not supported by kernel"
1440         fi
1441
1442         for p in $prog; do
1443                 [ ! -x "$p" ] && die "$prog is missing"
1444         done
1445 }
1446 check_initrd_fs
1447
1448 if [ -L "$target" ]; then
1449         target=$(readlink -f "$target")
1450 fi
1451
1452 if [ -n "$img_vers" ]; then
1453         target="$target-$kernel"
1454 fi
1455
1456 if [ -z "$force" -a -f "$target" ]; then
1457         die "$target already exists."
1458 fi
1459
1460 if [ ! -d "/lib/modules/$kernel" ]; then
1461         die "/lib/modules/$kernel is not a directory."
1462 fi
1463
1464 if [ "$kernel_version" -ge "002005" ]; then
1465         modext=".ko"
1466 fi
1467
1468 cache_modprobe_conf
1469
1470 for n in $PREMODS; do
1471         find_module "$n"
1472 done
1473
1474 if [ "$FBMODULE" ]; then
1475         find_module "$FBMODULE"
1476 fi
1477
1478 # autodetect USB keyboards
1479 find_modules_usbkbd
1480
1481 # allow forcing loading SCSI and/or IDE modules
1482 # XXX: where ADDSCSI cames from? drop?
1483 if is_yes "$ADDSCSI"; then
1484         find_modules_scsi
1485 fi
1486
1487 # autodetect SATA modules
1488 find_modules_sata
1489
1490 # XXX: where ADDIDE cames from? drop?
1491 if is_yes "$ADDIDE"; then
1492         find_modules_ide
1493 fi
1494
1495 if is_yes "$USE_SUSPEND"; then
1496         find_modules_suspend
1497 fi
1498
1499 find_root "$fstab" || exit
1500 verbose "Using $rootdev as device for rootfs"
1501
1502 find_modules_for_devpath "$rootdev"
1503
1504 # if USE_MULTIPATH is path to device, scan that too
1505 # this is to bootstrap multipath setup into initrd.
1506 if ! is_no "$USE_MULTIPATH" && ! is_yes "$USE_MULTIPATH"; then
1507         find_modules_multipath $USE_MULTIPATH
1508 fi
1509
1510 find_module "-$rootFs"
1511
1512 for n in $BASICMODULES; do
1513         find_module "$n"
1514 done
1515
1516 if is_yes "$USE_TUXONICE"; then
1517         find_module "-lzf"
1518 fi
1519
1520 find_modules_uvesafb
1521 find_modules_fbsplash
1522
1523 if [ -n "$ifneeded" -a -z "$MODULES" ]; then
1524         verbose "No modules are needed -- not building initrd image."
1525         exit 0
1526 fi
1527
1528 verbose "Building initrd..."
1529 DESTDIR=$(mktemp -d -t initrd.XXXXXX) || die "mktemp failed"
1530 RCFILE="$DESTDIR/linuxrc"
1531 > "$RCFILE"
1532 chmod a+rx "$RCFILE"
1533 ln -s linuxrc $DESTDIR/init
1534
1535 # create dirs that we really need
1536 inst_d /{lib,bin,etc,dev{,/pts,/shm},loopfs,var,proc,run,sys}
1537
1538 modules_install "$MODULES"
1539
1540 # mknod'ing the devices instead of copying them works both with and
1541 # without devfs...
1542 mknod -m 600 "$DESTDIR/dev/console" c 5 1
1543 mknod -m 666 "$DESTDIR/dev/null" c 1 3
1544 mknod -m 666 "$DESTDIR/dev/zero" c 1 5
1545 mknod -m 666 "$DESTDIR/dev/random" c 1 8
1546 mknod -m 666 "$DESTDIR/dev/urandom" c 1 9
1547 mknod -m 644 "$DESTDIR/dev/kmsg" c 1 11
1548
1549 inst_exec $busybox /bin/busybox
1550 ln -s busybox $DESTDIR/bin/sh
1551 # for older busyboxes who had /bin/initrd-busybox as EXEPATH
1552 ln -s busybox $DESTDIR/bin/initrd-busybox
1553
1554 add_linuxrc <<EOF
1555 #!/bin/sh
1556 # initrd generated by geninitrd/$VERSION
1557 # on $(LC_ALL=C date)
1558
1559 EOF
1560 load_font
1561 mount_proc
1562
1563 kmsg "geninitrd/$VERSION starting"
1564
1565 add_linuxrc <<-EOF
1566         # builtin defaults from geninitrd
1567         ROOT=$rootdev
1568         ROOTFS=$rootFs
1569 EOF
1570 add_linuxrc <<-'EOF'
1571         read CMDLINE < /proc/cmdline
1572
1573         for arg in $CMDLINE; do
1574                 if [ "${arg}" = "debuginitrd" ] || [ "${arg}" = "debugrd" ]; then
1575                         DEBUGINITRD=yes
1576                 fi
1577                 if [ "${arg##debuginitrd=}" != "${arg}" ] || [ "${arg##debugrd=}" != "${arg}" ]; then
1578                         DEBUGINITRD=${arg##debug*rd=}
1579                 fi
1580                 if [ "${arg##root=}" != "${arg}" ]; then
1581                         ROOT=${arg##root=}
1582                 fi
1583                 if [ "${arg##rootfs=}" != "${arg}" ]; then
1584                         ROOTFS=${arg##rootfs=}
1585                 fi
1586                 if [ "${arg##rootflags=}" != "${arg}" ]; then
1587                         ROOTFLAGS=${arg##rootflags=}
1588                 fi
1589                 if [ "${arg##rootfsflags=}" != "${arg}" ]; then
1590                         ROOTFSFLAGS=${arg##rootfsflags=}
1591                 fi
1592                 if [ "${arg##init=}" != "${arg}" ]; then
1593                         INIT=${arg##init=}
1594                 fi
1595         done
1596
1597         # handling of invalid, rootfsflags, option
1598         if [ -n "$ROOTFSFLAGS" ]; then
1599                 if [ -n "$ROOTFLAGS" ]; then
1600                         ROOTFLAGS="$ROOTFLAGS,$ROOTFSFLAGS"
1601                 else
1602                         ROOTFLAGS="$ROOTFSFLAGS"
1603                 fi
1604         fi
1605
1606         if [ "$DEBUGINITRD" = "sh" ]; then
1607                 # export some vars to subshell for debug to work
1608                 export CMDLINE ROOT ROOTFS ROOTDEV ROOTFLAGS DEBUGINITRD INIT
1609                 export LVM_ROOTVG LVM_SUSPENDVG LVM_VGVOLUMES
1610                 export rootnr attrs majmin major minor device
1611
1612                 # make debugshell() invoke subshell if $DEBUGINITRD=sh
1613                 debugshell() {
1614 EOF
1615 if is_yes "$RUN_SULOGIN_ON_ERR"; then
1616 add_linuxrc <<-'EOF'
1617         echo "debug shell disabled by RUN_SULOGIN_ON_ERR=yes from /etc/sysconfig/system during initrd generation time"
1618 EOF
1619 else
1620 add_linuxrc <<-'EOF'
1621         sh
1622 EOF
1623 fi
1624 add_linuxrc <<-'EOF'
1625                 }
1626         else
1627                 debugshell() {
1628                         :
1629                 }
1630         fi
1631
1632         if [ "$DEBUGINITRD" ]; then
1633                 set -x
1634         fi
1635 EOF
1636
1637 modules_add_linuxrc $MODULES
1638
1639 # TODO: rewrite for busybox
1640 #if [ -n "$loopDev" ]; then
1641 #       if [ ! -d /initrd ]; then
1642 #               mkdir /initrd
1643 #       fi
1644 #
1645 #       cp -a "$loopDev" "$DESTDIR/dev"
1646 #       cp -a "$rootdev" "$DESTDIR/dev"
1647 #       echo "echo Mounting device containing loopback root filesystem" >> "$RCFILE"
1648 #       echo "mount -t $loopFs $loopDev /loopfs" >> "$RCFILE"
1649 #       echo "echo Setting up loopback device $rootdev" >> $RCFILE
1650 #       echo "losetup $rootdev /loopfs$loopFile" >> "$RCFILE"
1651 #fi
1652
1653 if is_yes "$USE_UDEV"; then
1654         initrd_gen_udev
1655 else
1656         initrd_gen_mdev
1657 fi
1658
1659 initrd_gen_uvesafb
1660 initrd_gen_luks
1661 initrd_gen_dmraid
1662 initrd_gen_multipath
1663 initrd_gen_blkid
1664
1665 if is_yes "$have_nfs"; then
1666         initrd_gen_nfs
1667 else
1668         initrd_gen_md
1669         initrd_gen_lvm
1670         initrd_gen_bcache
1671         initrd_gen_blkid
1672         initrd_gen_luks
1673         initrd_gen_setrootdev
1674 fi
1675
1676 # additional devs always needed
1677 [ ! -e "$DESTDIR/$rootdev_add" ] && inst $rootdev_add /dev
1678
1679 initrd_gen_stop_udevd
1680 initrd_gen_stop_mdev
1681 initrd_gen_stop_uvesafb
1682
1683 # resume after killing local processes
1684 initrd_gen_tuxonice
1685 initrd_gen_suspend
1686
1687 # clean up env
1688 add_linuxrc <<-'EOF'
1689 if [ ! "$DEBUGINITRD" ]; then
1690         ifs=$IFS
1691         IFS="
1692         "
1693         for i in $(export -p); do
1694                 i=${i#declare -x } # ksh/bash
1695                 i=${i#export } # busybox
1696
1697                 case "$i" in
1698                 *=*)
1699                         : ;;
1700                 *)
1701                         continue ;;
1702                 esac
1703
1704                 i=${i%%=*}
1705
1706                 [ -z "$i" ] && continue
1707
1708                 case "$i" in
1709                         ROOT|PATH|HOME|TERM)
1710                                 :
1711                                 ;;
1712                         *)
1713                                 unset $i
1714                                 ;;
1715                 esac
1716         done
1717         IFS=$ifs
1718 fi
1719 EOF
1720
1721 if [ "$INITRDFS" = "initramfs" ]; then
1722         initrd_gen_initramfs_switchroot
1723 else
1724         umount_all
1725 fi
1726
1727 initrd_gen_fbsplash
1728 initrd_gen_fbcondecor
1729
1730 debug "Current /linuxrc:\n$(sed -e 's,^,| ,' $DESTDIR/linuxrc)"
1731
1732 IMAGE=$(mktemp -t initrd.img-XXXXXX) || die "mktemp failed"
1733
1734 IMAGESIZE=$(du -ks $DESTDIR | awk '{print int(($1+1023+512)/1024)*1024}')
1735 verbose "image size: $IMAGESIZE KiB ($DESTDIR)"
1736
1737 verbose "Creating $INITRDFS image $IMAGE"
1738 case "$INITRDFS" in
1739   ext2)
1740         dd if=/dev/zero of="$IMAGE" bs=1k count="$IMAGESIZE" 2> /dev/null
1741         # NOTE: ext2 label is max 16 chars
1742         mke2fs -q -F -b 1024 -m 0 -L "PLD/$kernel" "$IMAGE" 2>/dev/null 1>&2
1743         tune2fs -i 0 "$IMAGE" >/dev/null 2>&1
1744
1745         local tmpmnt=$(mktemp -d -t initrd.mnt-XXXXXX)
1746         debug "Mounting ext2 image $IMAGE to $tmpmnt"
1747         mount -o loop -t ext2 "$IMAGE" "$tmpmnt" || die "mount failed, check dmesg(1)"
1748         # We don't need this directory, so let's save space
1749         rm -rf "$tmpmnt"/lost+found
1750
1751         debug "Copy recursively $DESTDIR -> $tmpmnt"
1752         cp -a $DESTDIR/* $tmpmnt
1753         umount "$IMAGE"
1754         rmdir "$tmpmnt"
1755
1756         ;;
1757   rom|romfs)
1758         genromfs -f "$IMAGE" -d "$DESTDIR" -V "PLD Linux/$kernel (geninitrd/$VERSION)"
1759         ;;
1760   cram|cramfs)
1761         mkcramfs "$DESTDIR" "$IMAGE"
1762         ;;
1763   initramfs)
1764         (cd $DESTDIR; find . | cpio --quiet -H newc -o > "$IMAGE")
1765         ;;
1766   *)
1767         die "Filesystem $INITRDFS not supported by $PROGRAM"
1768 esac
1769
1770 CONFIG_BLK_DEV_RAM_SIZE=$(ikconfig | awk -F= '/^CONFIG_BLK_DEV_RAM_SIZE/{print $2}')
1771 if [ -z "$CONFIG_BLK_DEV_RAM_SIZE" ]; then
1772         CONFIG_BLK_DEV_RAM_SIZE=4096
1773         warn "No CONFIG_BLK_DEV_RAM_SIZE detected, fallback to $CONFIG_BLK_DEV_RAM_SIZE"
1774 fi
1775
1776 if [ "$IMAGESIZE" -gt $CONFIG_BLK_DEV_RAM_SIZE ]; then
1777         warn "Your image size is larger than $CONFIG_BLK_DEV_RAM_SIZE, Be sure to boot kernel with ramdisk_size=$IMAGESIZE!"
1778 fi
1779
1780 if ! is_no "$COMPRESS"; then
1781         compressor=$(find_compressor "$COMPRESS")
1782         verbose "Compressing $target with $compressor"
1783
1784         # TODO: the image name (specified from kernel.spec) already contains
1785         # extension, which is .gz most of the time.
1786         compress_image "$compressor" "$IMAGE" "$target" || {
1787                 if [ $compressor != gzip ]; then
1788                         warn "Could not compress with $compressor, retrying with gzip"
1789                         compress_image gzip "$IMAGE" "$target" || die "compress failed with gzip" $?
1790                 else
1791                         die "Could not compress image with $compressor"
1792                 fi
1793         }
1794 else
1795         cp -a "$IMAGE" "$target"
1796 fi
1797
1798 # XXX. check if bootsplash can output data to tmp dir not directly to initramfs image.
1799 initrd_gen_bootsplash "$target"
1800
1801 rm -rf "$DESTDIR" "$IMAGE"
1802
1803 # vim:ts=4:sw=4:noet:fdm=marker
This page took 0.15256 seconds and 2 git commands to generate.