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