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