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