#! /bin/sh ################################################################################ ## ## ## Copyright (c) International Business Machines Corp., 2001 ## ## ## ## This program is free software; you can redistribute it and#or modify ## ## it under the terms of the GNU General Public License as published by ## ## the Free Software Foundation; either version 2 of the License, or ## ## (at your option) any later version. ## ## ## ## This program is distributed in the hope that it will be useful, but ## ## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## ## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## ## for more details. ## ## ## ## You should have received a copy of the GNU General Public License ## ## along with this program; if not, write to the Free Software ## ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## ## ################################################################################ # File: mkrootfs # # Description: script to create rootfs that will fit on a floppy. This # filesystem contains a staticly linked busybox that provides # basic commands and a shell. # # Author: Manoj Iyer - manjo@mail.utexas.edu # # History: June 17 2003 - Created. # TWDIR=/tmp/mkrootfs.$$ # temporary working directory clean() { echo "INFO: Cleaning and exiting program" mount | grep "$TWDIR/mnt" 2>&1 >/dev/null && \ { echo "INFO: unmounting $TWDIR/mnt" umount $TWDIR/mnt 2>&1 >/dev/null || \ { echo "WARNING: failed unmounting temporary device." echo "WARNING: clean up temporary devices manually" } } rm -fr $TWDIR 2>&1 >/dev/null || \ { echo "WARNING: failed to remove temporary working directory" echo "WARNING: clean up temporary files and directories manually" } [ -a ./busybox-0.60.5.tar.gz ] && \ { rm ./busybox-0.60.5.tar.gz 2>&1 >/dev/null || \ { echo "WARNING: unable to remove busybox tarball" echo "WARNING: clean up temporary files and directories manually" } } } usage() { echo "Usage: `basename $0` [-b] -c -d -f -h" echo " " echo " " echo " -b location of the staticly linked busybox binary." echo " (if you dont provide one, this script will build one)" echo " -c creates rootfs on floppy." echo " (if this option is not provided rootfs.gz will be " echo " created in the current working directory.)" echo " -d options available are scsi or ide" echo " -f options available are ext2, ext3, reiserfs, xfs" echo " -h help" echo " " echo "Example: `basename $0` -b /tmp/busybox-dir/ -c -d ide -f ext2" exit 0 } help() { echo "This program will create a root file system with busybox commads." echo "Follow these steps to boot your machine with this file system" echo "1. create a boot floppy." echo " - use command: dd if=/bzImage of=/dev/fd0h1440 bs=1k" echo "2. create a root floppy " echo " - using this program eg: $0 -c -d scsi -f ext2 " echo "3. boot machine with kernel in boot floppy" echo " - provide boot options root=/dev/fd0h1440 (floppy device)" echo "4. insert root floppy when prompted by the kernel." echo "5. after you boot with this rootfs, remount '/' dir to read write" echo " - use command: mount -o remount -w rootfs / " echo " " echo " " usage } main() { local SYS_DIR=" " # names of various system directory local SYS_DEV=" " # names of various system devices local RC=0 # return value from commands. local FORCEREI=" " # force mkfs.reiserfs to be quite local CREATEFD=0 # flag to create floppy or just image local FSTYPE=ext2 # file system type default is ext2 local HDDTYPE=ide # HDD type SCSI or IDE default: ide local BBLOC="NONE" # location of static busybox binary. # parse input arguments while getopts b:cd:f:h arg do case $arg in b) BBLOC=$OPTARG;; c) CREATEFD=1;; d) HDDTYPE=$OPTARG;; f) FSTYPE=$OPTARG;; h) help;; \?) usage;; esac done # on exit clean up all temporary files and directories. trap "clean" 0 # create temporary working directory mkdir -p $TWDIR 2>&1 || \ { echo "FAILED: creating temporary working directory" exit 1 } # make block or character special files called ramdisk_fs mknod $TWDIR/ramdisk_fs b 1 0 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: creating block file $TWDIR/ramdisk_fs" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1; } # create a file system of required size, zeroing is important because # the filesystem will be compressed before its put on a floppy, zeroing # achives maximum compression. Creating a block file of size 8K. dd if=/dev/zero of=$TWDIR/ramdisk_fs bs=1k count=8 \ 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: unable create filesystem of 8K size" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } # create the filesystem, EXT2 file system will be default. if [ $FSTYPE == "ext2" ]; then mke2fs -v -m 0 -N 2000 $TWDIR/ramdisk_fs 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: unable to create EXT2 filesystem on block file." echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } else [ "$FSTYPE" == "reiserfs" ] && \ { FORCEREI="-f -f"; } mkfs.$FSTYPE $FORCEREI $TWDIR/ramdisk_fs 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: unable to create $FSTYPE filesystem on block file." echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } fi # mount this filesystem so that it can be populated with system files and # commands. # create a temporary mount directory. mkdir -p $TWDIR/mnt 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: creating temporary mount directory" exit 1 } mount -o loop $TWDIR/ramdisk_fs $TWDIR/mnt 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: unable to mount block file TWDIR/ramdisk_fs on $TWDIR/mnt" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } # remove lost+found directory from the rootfs file system, this is not # required. rm -fr $TWDIR/mnt/lost+found 2>&1 >$TWDIR/crfs.out || \ { echo "WARNING: unable to remove lost+found from $TWDIR/mnt/ directory" echo "WARNING: `cat $TWDIR/crfs.out`" } # create system directories. for SYS_DIR in bin boot dev etc etc/init.d etc/rc.d lib mnt opt proc \ root sbin tmp usr usr/bin usr/sbin usr/lib usr/share \ var var/lock var/log var/run var/lib/rpm do mkdir -p $TWDIR/mnt/$SYS_DIR 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: creating $SYS_DIR" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } done # initialize RPM database, just in case any RPMs will be installed to this # root filesystem. rpm --initdb --root=$TWDIR/mnt 2>&1 >$TWDIR/crfs.out || \ { echo "WARNING: initializing RPM database." echo "WARNING: cat `$TWDIR/crfs.out`" } # setting up the /etc directory, the three main files that will # be created are fstab, rc.sysinit and inittab. # create the inittab file. cat > $TWDIR/mnt/etc/inittab <<-EOF || RC=$? ::sysinit:/etc/rc.d/rc.sysinit ::askfirst:/bin/sh EOF [ $RC -ne 0 ] && \ { echo "FAILED: creating inittab file" exit 1 } # changing perissions if inittab file to 644 chmod 644 $TWDIR/mnt/etc/inittab 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: changing permissions of $TWDIR/mnt/etc/inittab" exit 1 } # create a /etc/rc.d/rc.sysinit file. cat > $TWDIR/mnt/etc/rc.d/rc.sysinit <<-EOF || RC=$? #!/bin/sh mount -a -n EOF [ $RC -ne 0 ] && \ { echo "FAILED: creating rc.sysinit file" exit 1 } # changing perissions of rc.sysinit file to 755 chmod 755 $TWDIR/mnt/etc/rc.d/rc.sysinit 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: changing permissions of $TWDIR/mnt/etc/rc.d/rc.sysinit" exit 1 } # creating etc/fstab file. cat > $TWDIR/mnt/etc/fstab <<-EOF || RC=$? /dev/ram0 / ext2 defaults 0 0 dev/fd0 / ext2 defaults 0 0 /proc /proc proc defaults 0 0 none /tmp tmpfs defaults 0 0 EOF [ $RC -ne 0 ] && \ { echo "FAILED: creating etc/fstab file" exit 1 } # changing perissions of rc.sysinit file to 644 chmod 644 $TWDIR/mnt/etc/fstab 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: changing permissions of $TWDIR/mnt/etc/fstab" exit 1 } # setting up /dev directory. Assuming that this script is # executed on a linux system, contents of /dev directory of the # host system will simply be copied to the rootfs file. Alternatively # the mknod command may be used to create # each device file. But the former is quick and easy. # set up floppy drives. /dev/null and /dev/console for SYS_DEV in /dev/fd[01]* /dev/null /dev/console /dev/zero do cp -dpR $SYS_DEV $TWDIR/mnt/dev 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: creating $SYS_DEV on $TWDIR/mnt/dev" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } done # set up scsi or ide devices. if [ "$HDDTYPE" == "scsi" ] || [ "$HDDTYPE" == "SCSI" ] then # set up SCSI cdrom drives. cp -dpR /dev/sr0 $TWDIR/mnt/dev 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: creating SCSI cdrom device on $TWDIR/mnt/dev" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } # set up SCSI hard drives. cp -dpR /dev/sd* $TWDIR/mnt/dev 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: creating SCSI cdrom device on $TWDIR/mnt/dev" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } elif [ "$HDDTYPE" == "ide" ] || [ "$HDDTYPE" == "IDE" ] ; then # set up IDE cdrom drive. cp -dpR /dev/cdrom $TWDIR/mnt/dev 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: creating SCSI cdrom device on $TWDIR/mnt/dev" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } # set up IDE hard drives. cp -dpR /dev/hd* $TWDIR/mnt/dev 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: creating SCSI cdrom device on $TWDIR/mnt/dev" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } else echo "FAILED: unknown hardware type:" usage fi # setting up busybox. if [ "$BBLOC" == "NONE" ] then echo "ĪNFO: downloading busybox from www.busybox.net" wget -q -c http://www.busybox.net/downloads/busybox-0.60.5.tar.gz \ 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: fetching busybox from www.busybox.net" exit 1 } tar zxf ./busybox-0.60.5.tar.gz 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: uncompressing busybox tar ball" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } mv ./busybox-0.60.5 $TWDIR/ 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: moving busybox dir to temporary working dir" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } echo "INFO: Compiling static busybox... this will take few minutes" make -C $TWDIR/busybox-0.60.5 clean 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: compiling static busybox." echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } make -C $TWDIR/busybox-0.60.5 DOSTATIC=true 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: compiling static busybox." echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } cp $TWDIR/busybox-0.60.5/busybox $TWDIR/mnt/bin/ 2>&1 \ >$TWDIR/crfs.out || \ { echo "FAILED: copying busybox binary to $TWDIR/mnt/bin/" exit 1 } elif [ -z $BBLOC ]; then echo "FAILED: bad path for static busybox" usage else cp $BBLOC/busybox $TWDIR/mnt/bin/ 2>&1 \ >$TWDIR/crfs.out || \ { echo "FAILED: copying busybox binary to $TWDIR/mnt/bin/" exit 1 } fi echo "INFO: installing busybox" # set up / directory ln -f $TWDIR/mnt/bin/busybox $TWDIR/mnt/linuxrc 2>&1 \ >$TWDIR/crfs.out || \ { echo "FAILED: linking busybox to linuxrc" exit 1 } # set up /usr/sbin directory ln -f $TWDIR/mnt/bin/busybox $TWDIR/mnt/usr/sbin/chroot 2>&1 \ >$TWDIR/crfs.out || \ { echo "FAILED: linking busybox to chroot" exit 1 } # set up /bin directory for SYS_CMD in ash chmod dd false kill mknod pidof rmdir sync umount \ chown df grep ln more ps sed tar uname cat cp dmesg \ gunzip ls mount pwd sh touch zcat chgrp date echo gzip \ mkdir mv rm sleep true do ln -f $TWDIR/mnt/bin/busybox $TWDIR/mnt/bin/$SYS_CMD 2>&1 \ >$TWDIR/crfs.out || \ { echo "FAILED: linking busybox to $SYS_CMD" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } done # set up /sbin directory for SYS_CMD in halt klogd mkswap poweroff swapoff syslogd \ init lsmod modprobe reboot swapon do ln -f $TWDIR/mnt/bin/busybox $TWDIR/mnt/sbin/$SYS_CMD 2>&1 \ >$TWDIR/crfs.out || \ { echo "FAILED: linking busybox to $SYS_CMD" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } done # set up /usr/bin directory for SYS_CMD in clear du free killall sort \ tty wc xargs basename cut env head \ logger tail uniq which yes chvt dirname \ find id reset test uptime whoami do ln -f $TWDIR/mnt/bin/busybox $TWDIR/mnt/usr/bin/$SYS_CMD 2>&1 \ >$TWDIR/crfs.out || \ { echo "FAILED: linking busybox to $SYS_CMD" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } done # sync'ing changes to disk. sync; sync; sync; sync; sync; sync; echo "INFO: creating compressed file system" # creating compressed file system. dd if=$TWDIR/ramdisk_fs bs=1k | gzip -v9 > $TWDIR/rootfs.gz || \ { echo "FAILED: creating compressed file system." exit 1 } # create a copy of the rootfs.gz on PWD. cp $TWDIR/rootfs.gz ./ 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: coping rootfs.gz from temp directory to $PWD" echo "FAILED: `cat $TWDIR/crfs.out`" exit 1 } if [ $CREATEFD -ne 0 ] then # creating filesystem on floppy if [ $FSTYPE == "ext2" ]; then mke2fs -v -m 0 -N 24 /dev/fd0h1440 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: unable to create EXT2 filesystem on floppy" echo "FAILED: `cat $TWDIR/crfs.out`" echo "INFO: mke2fs -m 0 -N 24 /dev/fd0h1440" echo "INFO: and dd rootfs.gz to this floppy" exit 1 } else [ "$FSTYPE" == "reiserfs" ] && \ { FORCEREI="-f -f"; } mkfs.$FSTYPE $FORCEREI /dev/fd0h1440 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: unable to create $FSTYPE on floppy" echo "FAILED: `cat $TWDIR/crfs.out`" echo "INFO: mke2fs -m 0 -N 24 /dev/fd0h1440" echo "INFO: and dd rootfs.gz to this floppy" exit 1 } fi sync; sync; sync; sync # dd the rootfs on to floppy, if the rootfs.gz is greater than # dd will fail so no pre-check is done on size of rootfs.gz dd if=$TWDIR/rootfs.gz of=/dev/fd0h1440 bs=1k 2>&1 >$TWDIR/crfs.out || \ { echo "FAILED: dd'ing the rootfs.gz onto floppy." echo "FAILED: `cat $TWDIR/crfs.out`" echo "INFO: please try it manually" echo "INFO: dd if=./rootfs.gz of=/dev/fd0 bs=1k" exit 1 } exit 0 else echo "INFO: create floppy manually" echo "INFO: rootfs.gz in in $PWD directory" echo "INFO: dd if=./rootfs.gz of=/dev/fd0 bs=1k" exit 0 fi } main "$@"