Home | History | Annotate | Download | only in util
      1 #!/bin/sh
      2 # MaKe a Bootable IMAGE --- 1.44, 2.88 and El Torito no-emulation mode
      3 # C) 2001,2002,2003 Thierry Laronde <tlaronde (at] polynum.org>
      4 # C) 2001,2002,2003 Robert Millan <robertmh (at] gnu.org>
      5 
      6 
      7 # This program is free software; you can redistribute it and/or modify
      8 # it under the terms of the GNU General Public License as published by
      9 # the Free Software Foundation; either version 2, or (at your option)
     10 # any later version.
     11 #
     12 # This program is distributed in the hope that it will be useful,
     13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 # GNU General Public License for more details.
     16 #
     17 # You should have received a copy of the GNU General Public License
     18 # along with this program; if not, you can either send email to this
     19 # program's maintainer or write to: The Free Software Foundation,
     20 # Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.
     21 
     22 # $Id: mkbimage,v 1.19 2004/07/21 14:43:04 robertmh Exp $
     23 
     24 # Global variables
     25 tarfile=
     26 dir=
     27 fs= #file system type
     28 decompress=
     29 image_type=
     30 uname=`uname -s`
     31 PATH=/sbin:$PATH
     32 
     33 # You can set GRUB_PATH  if you need to use a specially located GRUB.
     34 # This MUST end by a '/'!
     35 
     36 
     37 #----------------------------DON'T CHANGE: INTERNALS
     38 
     39 block_size=512
     40 cylinders=
     41 heads=
     42 sectors=
     43 cyl_size=
     44 type_option=
     45 geo_option=
     46 image=
     47 bk_120=$((2 * 15 * 80))
     48 bk_144=$((2 * 18 * 80))
     49 bk_288=$((2 * 36 * 80))
     50 bk_160=$((2 * 20 * 80))
     51 bk_168=$((2 * 21 * 80))
     52 bk_174=$((2 * 21 * 83))
     53 lo_options=
     54 device_map=
     55 mkfs_options=
     56 debug=
     57 stage2_os_name=
     58 
     59 # Name by which this script was invoked.
     60 program=`echo "$0" | sed -e 's/[^\/]*\///g'`
     61 version_number='$Revision: 1.19 $'
     62 
     63 usage="
     64 Usage: $program [-hVF] [-t TYPE] [-d DIRECTORY] [-s FS_TYPE] -f TAR_FILE
     65 Make a Bootable IMAGE using GRUB as a bootloader
     66 
     67 Options:
     68  Actions:
     69  -d DIRECTORY [default CWD]
     70 	    Directory where the boot.image and the partition subdirectories
     71 	    are/will be created
     72  -f TAR_FILE
     73 	    Name of the tar file containing the filesystem to install. Can
     74 	    be a pure tar file [.tar] or a compressed tar file
     75 	    [.tar.gz|.tar.bz2]
     76  -s FS_TYPE
     77 	    Type of the file system to create on the virtual disk. Choices 
     78 	    are:
     79 		ext2 on GNU [default is ext2]
     80 		ext2, minix or msdos on GNU/Linux [default is ext2]
     81 
     82  -t TYPE
     83 	    Type of the image to create. Choices are '1.20', '1.44', '1.60',
     84 	    '1.68', '1.74', '2.88' or 'hd' [default is hd]
     85  -F
     86 	    Force to set the set_dpt flag (unnecessary 99% of the time! Be
     87 	    careful! 
     88  Informations:
     89  -D     
     90 	    turn Debugging on [xtrace]
     91  -h|--help	
     92 	    display this Help and exit
     93  -V|--version	
     94 	    display Version information and exit
     95 
     96 Copyright (c) 2001,2002,2003 Thierry Laronde <tlaronde (at] polynum.org>. 
     97 Copyright (c) 2001,2002 Robert Millan <zeratul2 (at] wanadoo.es>.
     98 GPLed."
     99 
    100 version="mkbimage $version_number
    101 
    102 Written by Thierry Laronde and Robert Millan.
    103 
    104 Copyright (c) 2001,2002,2003 Thierry Laronde <tlaronde (at] polynum.org>.
    105 Copyright (c) 2001,2002,2003 Robert Millan <zeratul2 (at] wanadoo.es>.
    106 
    107 This is free software under the GPL version 2 or later; see the source for 
    108 copying conditions.  There is NO warranty, not even for MERCHANTABILITY or 
    109 FITNESS FOR A PARTICULAR PURPOSE."
    110 
    111 # Functions
    112 
    113 error ()
    114 {
    115 	case $1 in
    116 	bug) echo "This is a bug!";
    117 		echo "$usage";;
    118 	option) echo "Unknow option"; echo "$usage";;
    119 	missing_argument) echo "You must give an argument to the option!";
    120 		echo "$usage";;
    121 	missing_option) echo "You must indicate at least one option!";
    122 		echo "$usage";;
    123 	must_be_root) echo "You must be root! (or install e2tools/mtools)";;
    124 	unknown_fs)	if [ $uname = Linux ];
    125 				then echo "The GNU/Linux supported fs are: ext2, minix or msdos!";
    126 			elif [ $uname = GNU ];
    127 				then echo "The GNU supported fs is ext2!";
    128 			fi;;
    129 	unknown_format) echo "The tar file must be .tar|.tar.gz|.tar.bz2!";;
    130 	wont_fit) echo "The files won't fit on the selected type of media!";;
    131 	wrong_directory) echo "Directory inexistant or not given!";
    132 		echo "$usage";;
    133 	wrong_file) echo "File inexistant or empty!";
    134 		echo "$usage";;
    135 	wrong_type) echo "The type specified is not a valid one!";
    136 		echo "$usage";;
    137 	esac	
    138 	exit 1
    139 }
    140 
    141 # create a filesystem of type $fs in $image with offset $offset
    142 mkbimage_mkfs ()
    143 {
    144   case $offset in
    145     0)  lo_options="";;
    146     *) lo_options="-o $offset";;
    147   esac
    148 
    149   if [ "$offset" = "0" ] ; then
    150     mkfs.$fs -F $image
    151   elif [ `id -u` = "0" ] ; then
    152     losetup $lo_options /dev/loop1 $image
    153     mkfs.$fs /dev/loop1
    154     losetup -d /dev/loop1
    155   else
    156     error must_be_root
    157   fi
    158 }
    159 
    160 # copy ${image}1/* to ${image}:/, assuming ${image} contains a filesystem
    161 # of type $fs in offset $offset
    162 mkbimage_cp ()
    163 {
    164   case $offset in
    165     0)  lo_options="";;
    166     *)  lo_options="-o $offset";;
    167   esac
    168   case $fs in
    169     ext2)
    170       cp="e2cp";
    171       mkdir="e2mkdir";;
    172     vfat)
    173       cp="mcopy";
    174       mkdir="mmd";;
    175     *)
    176       cp="";
    177       mkdir="";;
    178   esac
    179 
    180   if [ "$offset" = 0 ] && which $cp > /dev/null ; then
    181     for dir in $(cd ${image}1 && find -type d) ; do
    182 	$mkdir ${image}:$dir
    183     done
    184     for file in $(cd ${image}1 && find -type f) ; do
    185 	$cp ${image}1/$file ${image}:$file
    186     done
    187   elif [ "`id -u`" = "0" ] ; then
    188     losetup $lo_options /dev/loop1 $image
    189     mkdir ${image}.mnt
    190     mount -t $fs /dev/loop1 ${image}.mnt
    191     cp -a ${image}1/* ${image}.mnt/ && sync
    192     umount ${image}.mnt
    193     rmdir ${image}.mnt
    194     losetup -d /dev/loop1
    195   else
    196     error must_be_root
    197   fi
    198 }
    199 
    200 #**********************************************************************
    201 #                          MAIN PROGRAM                               *
    202 #**********************************************************************
    203 
    204 #---------------------- Getting the options
    205 
    206 [ $# -eq 0 ] && error missing_option;
    207 
    208 while [ $# -gt 0 ]; do
    209 	case "$1" in
    210 		-d) shift;
    211 			dir="$1";
    212 			[ ! -d "$1" ] && error wrong_directory;;
    213 		-f) shift;
    214 			tarfile="$1";
    215 			[ -z "$tarfile" ] && error missing_argument;;
    216 		-s) shift;
    217 			fs="$1";;
    218 		-t) shift;
    219 			image_type="$1";;
    220 		-F) geo_option="-F";;
    221 		-D) debug="-v";
    222 		    set -x;;
    223 		-h|--help) echo "$usage"; exit 0;;
    224 		-V|--version) echo "$version"; exit 0;;
    225 	 	*) error option ;;
    226 	esac
    227 shift	
    228 done
    229 #---------------------- Sanity checks
    230 [ ! "$tarfile" ] && error missing_argument;
    231 [ ! -s "$tarfile" ] && error wrong_file;
    232 
    233 if [ ! "$image_type" ]; then
    234 	image_type=hd;
    235 elif [ "$image_type" != "1.20" ] && [ "$image_type" != "1.44" ] \
    236   && [ "$image_type" != "1.60" ] && [ "$image_type" != "1.68" ] \
    237   && [ "$image_type" != "2.88" ] && [ "$image_type" != "1.74" ] \
    238   && [ "$image_type" != "hd" ] && [ "$image_type" != "1.60" ] ; then
    239   error wrong_type ;
    240 fi
    241 
    242 [ ! "$fs" ] && fs=ext2
    243 
    244 # Carlo Contavalli reported that I [TL] have forgotten to specify the
    245 # partition ID for sfdisk to correctly fill the partition table (ext2 is the
    246 # default on Linux, so this worked in this case...). This is fixed below.
    247 case "$fs" in
    248 	ext2) mkfs_options="-m 0";
    249 		  part_id="83";; # This is the default
    250 #	ufs)	if [ $uname = Linux ];
    251 #		then error unknown_fs;
    252 #		fi;;
    253 	minix)	if [ $uname = GNU ];
    254 		then error unknown_fs;
    255 		else 
    256 			mkfs_options="-v"; # Minix version 2
    257 			part_id="81";
    258 		fi;;
    259 	msdos)	if [ $uname = GNU ];
    260 		then error unknown_fs;
    261 		else 
    262 			mkfs_options="-f 1 -F 12"; # the smallest...
    263 			part_id="1"; 
    264 		fi;;
    265 	*) error unknown_fs;;
    266 esac
    267 
    268 # What type of tar file has been given ?
    269 
    270 suffix=`echo "$tarfile" | sed -n 's/^.*\.\([targbz2]\{2,3\}\)$/\1/p'`
    271 case "$suffix" in
    272 	tar) decompress="cat";;
    273 	gz) decompress="gunzip -c";;
    274 	bz2) decompress="bunzip2 -c";;
    275 	*) error unknown_format;;
    276 esac
    277 #---------------------- Initializations
    278 
    279 [ ! "$dir" ] && dir=`pwd`
    280 
    281 image=$dir/$image_type.image
    282 device_map=$dir/device.map
    283 
    284 # First, find the size of the tar file in block_size.
    285 file_size=`$decompress $tarfile | wc -c | tr -d ' '`
    286 file_size=$(($file_size / $block_size + 1))
    287 
    288 # Increase in order to be sure that with a fs there will be enough
    289 # room (trying 110%)
    290 file_size=$(($file_size + $file_size / 10))
    291 
    292 case "$image_type" in
    293   hd) heads=16;
    294     sectors=63;
    295     cyl_size=$((16 * 63));
    296     # Create the minimum number of cylinders. At the moment, we leave
    297     # some space by rounding everything up by adding 1 cylinder, plus
    298     # another one for MBR + reserved track.
    299     cylinders=$(($file_size / $cyl_size + 2));; 
    300   1.20) [ $file_size -ge $bk_120 ] && error wont_fit; 
    301     heads=2;
    302     sectors=15;
    303     cyl_size=$((2 * 15));
    304     cylinders=80;;
    305   1.44) [ $file_size -ge $bk_144 ] && error wont_fit; 
    306     heads=2;
    307     sectors=18;
    308     cyl_size=$((2 * 18));
    309     cylinders=80;;
    310   1.60) [ $file_size -ge $bk_160 ] && error wont_fit; 
    311     heads=2;
    312     sectors=20;
    313     cyl_size=$((2 * 20));
    314     cylinders=80;
    315     geo_option="-F";;
    316   1.68) [ $file_size -ge $bk_168 ] && error wont_fit; 
    317     heads=2;
    318     sectors=21;
    319     cyl_size=$((2 * 21));
    320     cylinders=80;;
    321   1.74) [ $file_size -ge $bk_174 ] && error wont_fit; 
    322     heads=2;
    323     sectors=21;
    324     cyl_size=$((2 * 21));
    325     cylinders=83;;
    326   2.88) [ $file_size -ge $bk_288 ] && error wont_fit;
    327     heads=2;
    328     sectors=36;
    329     cyl_size=$((2 * 36));
    330     cylinders=80;;
    331   *) error bug;;
    332 esac
    333 
    334 type_option="-t $image_type"
    335 
    336 # We start by creating a virtual disk which size is the number of
    337 # cylinders of $cyl_size mandatory to put the files stocked in the $tarfile
    338 # Create the empty virtual disk
    339 dd if=/dev/zero of=$image bs=$block_size count=$(($cyl_size * $cylinders))
    340 
    341 # We then format the virtual disk
    342 # NOTE: the El Torito specification wants only one partition. So we
    343 # create the first, and the remaining 3 entries are empty.
    344 
    345 if [ "$image_type" = "hd" ]; then
    346   sfdisk -C $cylinders -H $heads -S $sectors -D $image<<EOT
    347 ,,$part_id,*,0,1,1
    348 
    349 
    350 EOT
    351   offset="$(($sectors * $block_size))" 
    352   type_option=
    353 else
    354   offset="0"
    355 fi
    356 
    357 # It's time now to create the filesystem on the first partition.
    358 mkbimage_mkfs
    359 
    360 # then untar the files
    361 [ ! -e ${image}1 ] || { echo "${image}1 exists, please remove it first"; exit 1;}
    362 mkdir -p ${image}1
    363 $decompress $tarfile | tar -C ${image}1 $debug -xf -
    364 
    365 # copy the untarred files into the filesystem image
    366 mkbimage_cp
    367 
    368 #We verify that the stage2 exists and we search the name
    369 stage2_os_name=`find ${image}1 -name stage2 -type f`
    370 
    371 [ -r "$stage2_os_name" ] || { echo "I can't find stage2!"; exit 1;}
    372 
    373 #------------------------- GRUB stuff
    374 if [ "$image_type" = "hd" ]; then
    375 	device='(hd0)'
    376 	root='(hd0,0)'
    377 else
    378 	device='(fd0)'
    379 	root='(fd0)'
    380 fi
    381 
    382 cat<<EOT >$device_map
    383 $device	${image}
    384 EOT
    385 
    386 ${GRUB_PATH}grub --device-map=$device_map --batch<<EOT
    387 geometry $device $cylinders $heads $sectors
    388 root $root
    389 setup $device
    390 geometry $geo_option -w $type_option $device $cylinders $heads $sectors
    391 EOT
    392 
    393 echo "-------------------WHAT'S NEXT?-------------------------------------"
    394 echo
    395 
    396 cat <<EOF
    397 If you have created an image aimed to a floppy, then something like:
    398 
    399 dd if=<type>.image of=/dev/fd0[u<size>] bs=512
    400 
    401 will be more than enough... if you have formated the floppy correctly
    402 using \`superformat' to be found in \`fdutils' package.
    403 
    404 For El Torito floppy emulation :
    405 
    406 mkisofs -b <image> -c boot.catalog -o raw.iso <dir>
    407 
    408 And for El Torito Hard Disk emulation:
    409 
    410 mkisofs -b <image> -hard-disk-boot -c boot.catalog -o raw.iso <dir> 
    411 
    412 Enjoy!
    413 EOF
    414 
    415 rm -rf ${image}1
    416 
    417 exit 0
    418