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