]> git.pld-linux.org Git - projects/geninitrd.git/blob - geninitrd
USB keyboard modules finding and loading at initrd level.
[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 usbkbd
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 # autodetect USB keyboards
1161 find_modules_usbkbd
1162
1163 # allow forcing loading SCSI and/or IDE modules
1164 # XXX: where ADDSCSI cames from? drop?
1165 if is_yes "$ADDSCSI"; then
1166         find_modules_scsi
1167 fi
1168
1169 # autodetect SATA modules
1170 find_modules_sata
1171
1172 # XXX: where ADDIDE cames from? drop?
1173 if is_yes "$ADDIDE"; then
1174         find_modules_ide
1175 fi
1176
1177 if is_yes "$USE_SUSPEND"; then
1178         find_modules_suspend
1179 fi
1180
1181 find_root "$fstab" || exit
1182 debug "Using $rootdev as device for rootfs"
1183
1184 find_modules_for_devpath "$rootdev"
1185
1186 # if USE_MULTIPATH is path to device, scan that too
1187 # this is to bootstrap multipath setup into initrd.
1188 if ! is_no "$USE_MULTIPATH" && ! is_yes "$USE_MULTIPATH"; then
1189         find_modules_multipath $USE_MULTIPATH
1190 fi
1191
1192 find_module "-$rootFs"
1193
1194 for n in $BASICMODULES; do
1195         find_module "$n"
1196 done
1197
1198 if is_yes "$USE_TUXONICE"; then
1199         find_module "-lzf"
1200 fi
1201
1202 find_modules_fbsplash
1203
1204 if [ -n "$ifneeded" -a -z "$MODULES" ]; then
1205         debug "No modules are needed -- not building initrd image."
1206         exit 0
1207 fi
1208
1209 debug "Building initrd..."
1210 DESTDIR=$(mktemp -d -t initrd.XXXXXX) || die "mktemp failed"
1211 RCFILE="$DESTDIR/linuxrc"
1212 > "$RCFILE"
1213 chmod a+rx "$RCFILE"
1214 ln -s linuxrc $DESTDIR/init
1215
1216 # create dirs that we really need
1217 inst_d /{lib,bin,etc,dev{,/pts,/shm},loopfs,var,proc,sys}
1218
1219 modules_install "$MODULES"
1220
1221 # mknod'ing the devices instead of copying them works both with and
1222 # without devfs...
1223 mknod "$DESTDIR/dev/console" c 5 1
1224 mknod "$DESTDIR/dev/null" c 1 3
1225 mknod "$DESTDIR/dev/zero" c 1 5
1226 mknod "$DESTDIR/dev/random" c 1 8
1227 mknod "$DESTDIR/dev/urandom" c 1 9
1228
1229 inst_exec $busybox /bin/busybox
1230 ln -s busybox $DESTDIR/bin/sh
1231 # for older busyboxes who had /bin/initrd-busybox as EXEPATH
1232 ln -s busybox $DESTDIR/bin/initrd-busybox
1233
1234 add_linuxrc <<EOF
1235 #!/bin/sh
1236 # initrd generated by:
1237 # $GENINITRD_RCSID
1238
1239 EOF
1240 mount_proc
1241 add_linuxrc <<-'EOF'
1242         read CMDLINE < /proc/cmdline; export CMDLINE
1243
1244         for arg in $CMDLINE; do
1245                 if [ "${arg}" = "debuginitrd" ]; then
1246                         DEBUGINITRD=yes
1247                 fi
1248                 if [ "${arg##debuginitrd=}" != "${arg}" ]; then
1249                         DEBUGINITRD=${arg##debuginitrd=}
1250                 fi
1251                 if [ "${arg##root=}" != "${arg}" ]; then
1252                         ROOT=${arg##root=}
1253                 fi
1254                 if [ "${arg##rootfsflags=}" != "${arg}" ]; then
1255                         ROOTFSFLAGS=${arg##rootfsflags=}
1256                 fi
1257         done
1258
1259         # make debugshell() invoke subshell if $DEBUGINITRD=sh
1260         if [ "$DEBUGINITRD" = "sh" ]; then
1261                 debugshell() {
1262 EOF
1263 if is_yes "$RUN_SULOGIN_ON_ERR"; then
1264 add_linuxrc <<-'EOF'
1265         echo "debug shell disabled by /etc/sysconfig/system:RUN_SULOGIN_ON_ERR setting"
1266 EOF
1267 else
1268 add_linuxrc <<-'EOF'
1269         sh
1270 EOF
1271 fi
1272 add_linuxrc <<-'EOF'
1273                 }
1274         else
1275                 debugshell() {
1276                         :
1277                 }
1278         fi
1279
1280         if [ "$DEBUGINITRD" ]; then
1281                 set -x
1282         fi
1283 EOF
1284
1285 modules_add_linuxrc $MODULES
1286
1287 # TODO: rewrite for busybox
1288 #if [ -n "$loopDev" ]; then
1289 #       if [ ! -d /initrd ]; then
1290 #               mkdir /initrd
1291 #       fi
1292 #
1293 #       cp -a "$loopDev" "$DESTDIR/dev"
1294 #       cp -a "$rootdev" "$DESTDIR/dev"
1295 #       echo "echo Mounting device containing loopback root filesystem" >> "$RCFILE"
1296 #       echo "mount -t $loopFs $loopDev /loopfs" >> "$RCFILE"
1297 #       echo "echo Setting up loopback device $rootdev" >> $RCFILE
1298 #       echo "losetup $rootdev /loopfs$loopFile" >> "$RCFILE"
1299 #fi
1300
1301 if is_yes "$USE_UDEV"; then
1302         initrd_gen_udev
1303 fi
1304
1305 find_modules_uvesafb
1306 initrd_gen_uvesafb
1307
1308 initrd_gen_luks
1309 initrd_gen_dmraid
1310 initrd_gen_multipath
1311 initrd_gen_blkid
1312
1313 if is_yes "$have_nfs"; then
1314         initrd_gen_nfs
1315 else
1316         initrd_gen_md
1317         initrd_gen_lvm
1318         initrd_gen_luks
1319         initrd_gen_setrootdev
1320 fi
1321
1322 initrd_gen_tuxonice
1323 initrd_gen_suspend
1324
1325 # additional devs always needed
1326 [ ! -e "$DESTDIR/$rootdev_add" ] && inst $rootdev_add /dev
1327
1328 initrd_gen_stop_udevd
1329 initrd_gen_stop_uvesafb
1330
1331 if [ "$INITRDFS" = "initramfs" ]; then
1332         initrd_gen_initramfs_switchroot
1333 else
1334         umount_all
1335 fi
1336
1337 initrd_gen_fbsplash
1338 initrd_gen_fbcondecor
1339
1340 IMAGE=$(mktemp -t initrd.img-XXXXXX) || die "mktemp failed"
1341
1342 IMAGESIZE=$(du -ks $DESTDIR | awk '{print int(($1+1023+512)/1024)*1024}')
1343 debug "image size: $IMAGESIZE KiB ($DESTDIR)"
1344
1345 debug "Creating $INITRDFS image $IMAGE"
1346 case "$INITRDFS" in
1347   ext2)
1348         dd if=/dev/zero of="$IMAGE" bs=1k count="$IMAGESIZE" 2> /dev/null
1349         # NOTE: ext2 label is max 16 chars
1350         mke2fs -q -F -b 1024 -m 0 -L "PLD/$kernel" "$IMAGE" 2>/dev/null 1>&2
1351         tune2fs -i 0 "$IMAGE" >/dev/null 2>&1
1352
1353         local tmpmnt=$(mktemp -d -t initrd.mnt-XXXXXX)
1354         debug "Mounting ext2 image $IMAGE to $tmpmnt"
1355         mount -o loop -t ext2 "$IMAGE" "$tmpmnt" || die "mount failed, check dmesg(1)"
1356         # We don't need this directory, so let's save space
1357         rm -rf "$tmpmnt"/lost+found
1358
1359         debug "Copy recursively $DESTDIR -> $tmpmnt"
1360         cp -a $DESTDIR/* $tmpmnt
1361         umount "$IMAGE"
1362         rmdir "$tmpmnt"
1363
1364         ;;
1365   rom|romfs)
1366         genromfs -f "$IMAGE" -d "$DESTDIR" -V "PLD Linux/$kernel (geninitrd/$VERSION)"
1367         ;;
1368   cram|cramfs)
1369         mkcramfs "$DESTDIR" "$IMAGE"
1370         ;;
1371   initramfs)
1372         (cd $DESTDIR; find . | cpio --quiet -H newc -o > "$IMAGE")
1373         ;;
1374   *)
1375         die "Filesystem $INITRDFS not supported by $PROGRAM"
1376 esac
1377
1378 CONFIG_BLK_DEV_RAM_SIZE=$(ikconfig | awk -F= '/^CONFIG_BLK_DEV_RAM_SIZE/{print $2}')
1379 if [ -z "$CONFIG_BLK_DEV_RAM_SIZE" ]; then
1380         CONFIG_BLK_DEV_RAM_SIZE=4096
1381 fi
1382
1383 if [ "$IMAGESIZE" -gt $CONFIG_BLK_DEV_RAM_SIZE ]; then
1384         warn "Your image size is larger than $CONFIG_BLK_DEV_RAM_SIZE, Be sure to boot kernel with ramdisk_size=$IMAGESIZE!"
1385 fi
1386
1387 if ! is_no "$COMPRESS"; then
1388         compressor=$(find_compressor "$COMPRESS")
1389         debug "Compressing $target with $compressor"
1390
1391         # TODO: the image name (specified from kernel.spec) already contains
1392         # extension, which is .gz most of the time.
1393         compress_image "$compressor" "$IMAGE" "$target" || {
1394                 if [ $compressor != gzip ]; then
1395                         warn "Could not compress with $compressor, retrying with gzip"
1396                         compress_image gzip "$IMAGE" "$target" || die "compress failed with gzip" $?
1397                 else
1398                         die "Could not compress image with $compressor"
1399                 fi
1400         }
1401 else
1402         cp -a "$IMAGE" "$target"
1403 fi
1404
1405 # XXX. check if bootsplash can output data to tmp dir not directly to initramfs image.
1406 initrd_gen_bootsplash "$target"
1407
1408 rm -rf "$DESTDIR" "$IMAGE"
1409
1410 # vim:ts=4:sw=4:noet:fdm=marker
This page took 0.279082 seconds and 3 git commands to generate.