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