eltorito.c revision 1.5
1/* 2 * Program eltorito.c - Handle El Torito specific extensions to iso9660. 3 * 4 5 Written by Michael Fulbright <msf@redhat.com> (1996). 6 7 Copyright 1996 RedHat Software, Incorporated 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2, or (at your option) 12 any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 22 23 24 25#include <stdio.h> 26#include <sys/types.h> 27#include <sys/stat.h> 28#include <unistd.h> 29#include <fcntl.h> 30#include <stdlib.h> 31 32#include "config.h" 33#include "mkisofs.h" 34#include "iso9660.h" 35 36/* used by Win32 for opening binary file - not used by Unix */ 37#ifndef O_BINARY 38#define O_BINARY 0 39#endif /* O_BINARY */ 40 41#undef MIN 42#define MIN(a, b) (((a) < (b))? (a): (b)) 43 44static struct eltorito_validation_entry valid_desc; 45static struct eltorito_defaultboot_entry default_desc; 46static struct eltorito_boot_descriptor gboot_desc; 47static struct eltorito_sectionheader_entry shdr_desc; 48static struct eltorito_defaultboot_entry efi_desc; 49 50static int tvd_write __PR((FILE * outfile)); 51 52/* 53 * Check for presence of boot catalog. If it does not exist then make it 54 */ 55void FDECL1(init_boot_catalog, const char *, path) 56{ 57 58 int bcat; 59 char * bootpath; /* filename of boot catalog */ 60 char * buf; 61 struct stat statbuf; 62 63 bootpath = (char *) e_malloc(strlen(boot_catalog)+strlen(path)+2); 64 strcpy(bootpath, path); 65 if (bootpath[strlen(bootpath)-1] != '/') 66 { 67 strcat(bootpath,"/"); 68 } 69 70 strcat(bootpath, boot_catalog); 71 72 /* 73 * check for the file existing 74 */ 75#ifdef DEBUG_TORITO 76 fprintf(stderr,"Looking for boot catalog file %s\n",bootpath); 77#endif 78 79 if (!stat_filter(bootpath, &statbuf)) 80 { 81 /* 82 * make sure its big enough to hold what we want 83 */ 84 if (statbuf.st_size == 2048) 85 { 86 /* 87 * printf("Boot catalog exists, so we do nothing\n"); 88 */ 89 free(bootpath); 90 return; 91 } 92 else 93 { 94 fprintf(stderr, "A boot catalog exists and appears corrupted.\n"); 95 fprintf(stderr, "Please check the following file: %s.\n",bootpath); 96 fprintf(stderr, "This file must be removed before a bootable CD can be done.\n"); 97 free(bootpath); 98 exit(1); 99 } 100 } 101 102 /* 103 * file does not exist, so we create it 104 * make it one CD sector long 105 */ 106 bcat = open(bootpath, O_WRONLY | O_CREAT | O_BINARY, S_IROTH | S_IRGRP | S_IRWXU ); 107 if (bcat == -1) 108 { 109 fprintf(stderr, "Error creating boot catalog, exiting...\n"); 110 perror(""); 111 exit(1); 112 } 113 114 buf = (char *) e_malloc( 2048 ); 115 write(bcat, buf, 2048); 116 close(bcat); 117 free(bootpath); 118} /* init_boot_catalog(... */ 119 120void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) 121{ 122 int bootcat; 123 int checksum; 124 unsigned char * checksum_ptr; 125 struct directory_entry * de = NULL; 126 struct directory_entry * de2; 127 struct directory_entry * efi_de = NULL; 128 int i; 129 int nsectors; 130 131 memset(boot_desc, 0, sizeof(*boot_desc)); 132 boot_desc->id[0] = 0; 133 memcpy(boot_desc->id2, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID) - 1); 134 boot_desc->version[0] = 1; 135 136 memcpy(boot_desc->system_id, EL_TORITO_ID, sizeof(EL_TORITO_ID)); 137 138 /* 139 * search from root of iso fs to find boot catalog 140 */ 141 de2 = search_tree_file(root, boot_catalog); 142 if (!de2) 143 { 144 fprintf(stderr,"Uh oh, I cant find the boot catalog!\n"); 145 exit(1); 146 } 147 148 set_731(boot_desc->bootcat_ptr, 149 (unsigned int) get_733(de2->isorec.extent)); 150 151 /* 152 * now adjust boot catalog 153 * lets find boot image first 154 */ 155 if (boot_image != NULL) 156 de=search_tree_file(root, boot_image); 157 if (efi_boot_image != NULL) 158 efi_de=search_tree_file(root, efi_boot_image); 159 160 if (de == NULL && efi_boot_image == NULL) 161 { 162 fprintf(stderr,"Uh oh, I cant find the boot image!\n"); 163 exit(1); 164 } 165 166 /* 167 * we have the boot image, so write boot catalog information 168 * Next we write out the primary descriptor for the disc 169 */ 170 memset(&valid_desc, 0, sizeof(valid_desc)); 171 valid_desc.headerid[0] = 1; 172 valid_desc.arch[0] = 173 (boot_image != NULL)? EL_TORITO_ARCH_x86 : EL_TORITO_ARCH_EFI; 174 175 /* 176 * we'll shove start of publisher id into id field, may get truncated 177 * but who really reads this stuff! 178 */ 179 if (publisher) 180 memcpy_max(valid_desc.id, publisher, MIN(23, strlen(publisher))); 181 182 valid_desc.key1[0] = 0x55; 183 valid_desc.key2[0] = 0xAA; 184 185 /* 186 * compute the checksum 187 */ 188 checksum=0; 189 checksum_ptr = (unsigned char *) &valid_desc; 190 for (i=0; i<sizeof(valid_desc); i+=2) 191 { 192 /* 193 * skip adding in ckecksum word, since we dont have it yet! 194 */ 195 if (i == 28) 196 { 197 continue; 198 } 199 checksum += (unsigned int)checksum_ptr[i]; 200 checksum += ((unsigned int)checksum_ptr[i+1])*256; 201 } 202 203 /* 204 * now find out the real checksum 205 */ 206 checksum = -checksum; 207 set_721(valid_desc.cksum, (unsigned int) checksum); 208 209 if (de == NULL) 210 goto skip_x86; 211 /* 212 * now make the initial/default entry for boot catalog 213 */ 214 memset(&default_desc, 0, sizeof(default_desc)); 215 default_desc.boot_id[0] = EL_TORITO_BOOTABLE; 216 217 /* 218 * use default BIOS loadpnt 219 */ 220 set_721(default_desc.loadseg, 0); 221 default_desc.arch[0] = EL_TORITO_ARCH_x86; 222 223 /* 224 * figure out size of boot image in sectors, for now hard code to 225 * assume 512 bytes/sector on a bootable floppy 226 */ 227 nsectors = ((de->size + 511) & ~(511))/512; 228#ifdef APPLE_HYB 229 /* NON-HFS change */ 230 if (verbose > 0 ) 231#endif /* APPLE_HYB */ 232 fprintf(stderr, "\nSize of boot image is %d sectors -> ", nsectors); 233 234 /* 235 * choose size of emulated floppy based on boot image size 236 */ 237 if (nsectors == 2880 ) 238 { 239 default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP; 240#ifdef APPLE_HYB 241 /* NON-HFS change */ 242 if (verbose > 0 ) 243#endif /* APPLE_HYB */ 244 fprintf(stderr, "Emulating a 1.44 meg floppy\n"); 245 } 246 else if (nsectors == 5760 ) 247 { 248 default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP; 249#ifdef APPLE_HYB 250 /* NON-HFS change */ 251 if (verbose > 0 ) 252#endif /* APPLE_HYB */ 253 fprintf(stderr,"Emulating a 2.88 meg floppy\n"); 254 } 255 else if (nsectors == 2400 ) 256 { 257 default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP; 258#ifdef APPLE_HYB 259 /* NON-HFS change */ 260 if (verbose > 0 ) 261#endif /* APPLE_HYB */ 262 fprintf(stderr,"Emulating a 1.2 meg floppy\n"); 263 } 264 else if (nsectors == 4 ) 265 { 266 default_desc.boot_media[0] = EL_TORITO_MEDIA_NOEMUL; 267#ifdef APPLE_HYB 268 /* NON-HFS change */ 269 if (verbose > 0 ) 270#endif /* APPLE_HYB */ 271 fprintf(stderr,"No-emulation CD boot sector\n"); 272 } 273 else 274 { 275 fprintf(stderr,"\nError - boot image is not the an allowable size.\n"); 276 exit(1); 277 } 278 279 280 /* 281 * FOR NOW LOAD 1 SECTOR, JUST LIKE FLOPPY BOOT, unless it's no-emulation 282 * boot. 283 */ 284 if (default_desc.boot_media[0] != EL_TORITO_MEDIA_NOEMUL) 285 nsectors = 1; 286 set_721(default_desc.nsect, (unsigned int) nsectors ); 287#ifdef DEBUG_TORITO 288 fprintf(stderr,"Extent of boot images is %d\n",get_733(de->isorec.extent)); 289#endif 290 set_731(default_desc.bootoff, 291 (unsigned int) get_733(de->isorec.extent)); 292 skip_x86: 293 /* 294 * add the EFI boot image, if specified 295 */ 296 if (efi_de != NULL) { 297 if (de != NULL) { 298 memset(&shdr_desc, 0, sizeof(shdr_desc)); 299 shdr_desc.header_id[0] = EL_TORITO_SHDR_ID_LAST_SHDR; 300 shdr_desc.platform_id[0] = EL_TORITO_ARCH_EFI; 301 set_721(shdr_desc.entry_count, 1); 302 } 303 304 memset(&efi_desc, 0, sizeof(efi_desc)); 305 efi_desc.boot_id[0] = EL_TORITO_BOOTABLE; 306 set_721(efi_desc.loadseg, 0); 307 efi_desc.arch[0] = EL_TORITO_ARCH_EFI; 308 309 nsectors = ((efi_de->size + 511) & ~(511))/512; 310 set_721(efi_desc.nsect, nsectors); 311 set_731(efi_desc.bootoff, (unsigned int)get_733(efi_de->isorec.extent)); 312 } 313 314 /* 315 * now write it to disk 316 */ 317 bootcat = open(de2->whole_name, O_RDWR | O_BINARY); 318 if (bootcat == -1) 319 { 320 fprintf(stderr,"Error opening boot catalog for update.\n"); 321 perror(""); 322 exit(1); 323 } 324 325 /* 326 * write out 327 */ 328 write(bootcat, &valid_desc, 32); 329 if (de != NULL) 330 { 331 write(bootcat, &default_desc, 32); 332 if (efi_de != NULL) 333 write(bootcat, &shdr_desc, sizeof(shdr_desc)); 334 } 335 if (efi_de != NULL) 336 write(bootcat, &efi_desc, sizeof(efi_desc)); 337 close(bootcat); 338} /* get_torito_desc(... */ 339 340/* 341 * Function to write the EVD for the disc. 342 */ 343static int FDECL1(tvd_write, FILE *, outfile) 344{ 345 /* 346 * Next we write out the boot volume descriptor for the disc 347 */ 348 get_torito_desc(&gboot_desc); 349 xfwrite(&gboot_desc, 1, 2048, outfile); 350 last_extent_written ++; 351 return 0; 352} 353 354struct output_fragment torito_desc = {NULL, oneblock_size, NULL, tvd_write}; 355