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