/* * Program eltorito.c - Handle El Torito specific extensions to iso9660. * Written by Michael Fulbright <msf@redhat.com> (1996). Copyright 1996 RedHat Software, Incorporated Copyright (C) 2009 Free Software Foundation, Inc. Boot Info Table generation based on code from genisoimage.c (from cdrkit 1.1.9), which was originally licensed under GPLv2+. 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 3, 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, see <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <errno.h> #include "config.h" #include "mkisofs.h" #include "iso9660.h" /* used by Win32 for opening binary file - not used by Unix */ #ifndef O_BINARY #define O_BINARY 0 #endif /* O_BINARY */ #undef MIN #define MIN(a, b) (((a) < (b))? (a): (b)) static struct eltorito_validation_entry valid_desc; static struct eltorito_defaultboot_entry default_desc; static struct eltorito_boot_descriptor gboot_desc; static int tvd_write __PR((FILE * outfile)); /* * Check for presence of boot catalog. If it does not exist then make it */ void FDECL1(init_boot_catalog, const char *, path) { FILE *bcat; char * bootpath; /* filename of boot catalog */ char * buf; struct stat statbuf; bootpath = (char *) e_malloc(strlen(boot_catalog)+strlen(path)+2); strcpy(bootpath, path); if (bootpath[strlen(bootpath)-1] != '/') { strcat(bootpath,"/"); } strcat(bootpath, boot_catalog); /* * check for the file existing */ #ifdef DEBUG_TORITO fprintf(stderr,"Looking for boot catalog file %s\n",bootpath); #endif if (!stat_filter(bootpath, &statbuf)) { /* * make sure its big enough to hold what we want */ if (statbuf.st_size == 2048) { /* * printf("Boot catalog exists, so we do nothing\n"); */ free(bootpath); return; } else { fprintf (stderr, _("A boot catalog exists and appears corrupted.\n")); fprintf (stderr, _("Please check the following file: %s.\n"), bootpath); fprintf (stderr, _("This file must be removed before a bootable CD can be done.\n")); free (bootpath); exit (1); } } /* * file does not exist, so we create it * make it one CD sector long */ bcat = fopen (bootpath, "wb"); if (bcat == NULL) error (1, errno, _("Error creating boot catalog (%s)"), bootpath); buf = (char *) e_malloc( 2048 ); if (fwrite (buf, 1, 2048, bcat) != 2048) error (1, errno, _("Error writing to boot catalog (%s)"), bootpath); fclose (bcat); chmod (bootpath, S_IROTH | S_IRGRP | S_IRWXU); free(bootpath); } /* init_boot_catalog(... */ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) { FILE *bootcat; int checksum; unsigned char * checksum_ptr; struct directory_entry * de; struct directory_entry * de2; unsigned int i; int nsectors; memset(boot_desc, 0, sizeof(*boot_desc)); boot_desc->id[0] = 0; memcpy(boot_desc->id2, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); boot_desc->version[0] = 1; memcpy(boot_desc->system_id, EL_TORITO_ID, sizeof(EL_TORITO_ID)); /* * search from root of iso fs to find boot catalog */ de2 = search_tree_file(root, boot_catalog); if (!de2) { fprintf (stderr, _("Boot catalog cannot be found!\n")); exit (1); } set_731(boot_desc->bootcat_ptr, (unsigned int) get_733(de2->isorec.extent)); /* * now adjust boot catalog * lets find boot image first */ de=search_tree_file(root, boot_image); if (!de) { fprintf (stderr, _("Boot image cannot be found!\n")); exit (1); } /* * we have the boot image, so write boot catalog information * Next we write out the primary descriptor for the disc */ memset(&valid_desc, 0, sizeof(valid_desc)); valid_desc.headerid[0] = 1; valid_desc.arch[0] = EL_TORITO_ARCH_x86; /* * we'll shove start of publisher id into id field, may get truncated * but who really reads this stuff! */ if (publisher) memcpy_max(valid_desc.id, publisher, MIN(23, strlen(publisher))); valid_desc.key1[0] = 0x55; valid_desc.key2[0] = 0xAA; /* * compute the checksum */ checksum=0; checksum_ptr = (unsigned char *) &valid_desc; for (i=0; i<sizeof(valid_desc); i+=2) { /* * skip adding in ckecksum word, since we dont have it yet! */ if (i == 28) { continue; } checksum += (unsigned int)checksum_ptr[i]; checksum += ((unsigned int)checksum_ptr[i+1])*256; } /* * now find out the real checksum */ checksum = -checksum; set_721(valid_desc.cksum, (unsigned int) checksum); /* * now make the initial/default entry for boot catalog */ memset(&default_desc, 0, sizeof(default_desc)); default_desc.boot_id[0] = EL_TORITO_BOOTABLE; /* * use default BIOS loadpnt */ set_721(default_desc.loadseg, 0); default_desc.arch[0] = EL_TORITO_ARCH_x86; /* * figure out size of boot image in sectors, for now hard code to * assume 512 bytes/sector on a bootable floppy */ nsectors = ((de->size + 511) & ~(511))/512; fprintf (stderr, _("\nSize of boot image is %d sectors"), nsectors); fprintf (stderr, " -> "); if (! use_eltorito_emul_floppy) { default_desc.boot_media[0] = EL_TORITO_MEDIA_NOEMUL; fprintf (stderr, _("No emulation\n")); } else if (nsectors == 2880 ) /* * choose size of emulated floppy based on boot image size */ { default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP; fprintf (stderr, _("Emulating a 1.44 meg floppy\n")); } else if (nsectors == 5760 ) { default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP; fprintf (stderr, _("Emulating a 2.88 meg floppy\n")); } else if (nsectors == 2400 ) { default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP; fprintf (stderr, _("Emulating a 1.2 meg floppy\n")); } else { fprintf (stderr, _("\nError - boot image is not the an allowable size.\n")); exit (1); } /* * FOR NOW LOAD 1 SECTOR, JUST LIKE FLOPPY BOOT!!! */ nsectors = 1; set_721(default_desc.nsect, (unsigned int) nsectors ); #ifdef DEBUG_TORITO fprintf(stderr,"Extent of boot images is %d\n",get_733(de->isorec.extent)); #endif set_731(default_desc.bootoff, (unsigned int) get_733(de->isorec.extent)); /* * now write it to disk */ bootcat = fopen (de2->whole_name, "r+b"); if (bootcat == NULL) error (1, errno, _("Error opening boot catalog for update")); /* * write out */ if (fwrite (&valid_desc, 1, 32, bootcat) != 32) error (1, errno, _("Error writing to boot catalog")); if (fwrite (&default_desc, 1, 32, bootcat) != 32) error (1, errno, _("Error writing to boot catalog")); fclose (bootcat); /* If the user has asked for it, patch the boot image */ if (use_boot_info_table) { FILE *bootimage; uint32_t bi_checksum; unsigned int total_len; static char csum_buffer[SECTOR_SIZE]; int len; struct eltorito_boot_info bi_table; bootimage = fopen (de->whole_name, "r+b"); if (bootimage == NULL) error (1, errno, _("Error opening boot image file '%s' for update"), de->whole_name); /* Compute checksum of boot image, sans 64 bytes */ total_len = 0; bi_checksum = 0; while ((len = fread (csum_buffer, 1, SECTOR_SIZE, bootimage)) > 0) { if (total_len & 3) error (1, 0, _("Odd alignment at non-end-of-file in boot image '%s'"), de->whole_name); if (total_len < 64) memset (csum_buffer, 0, 64 - total_len); if (len < SECTOR_SIZE) memset (csum_buffer + len, 0, SECTOR_SIZE - len); for (i = 0; i < SECTOR_SIZE; i += 4) bi_checksum += get_731 (&csum_buffer[i]); total_len += len; } if (total_len != de->size) error (1, 0, _("Boot image file '%s' changed unexpectedly"), de->whole_name); /* End of file, set position to byte 8 */ fseeko (bootimage, (off_t) 8, SEEK_SET); memset (&bi_table, 0, sizeof (bi_table)); /* Is it always safe to assume PVD is at session_start+16? */ set_731 (bi_table.pvd_addr, session_start + 16); set_731 (bi_table.file_addr, de->starting_block); set_731 (bi_table.file_length, de->size); set_731 (bi_table.file_checksum, bi_checksum); if (fwrite (&bi_table, 1, sizeof (bi_table), bootimage) != sizeof (bi_table)) error (1, errno, _("Error writing to boot image (%s)"), bootimage); fclose (bootimage); } } /* get_torito_desc(... */ /* * Function to write the EVD for the disc. */ static int FDECL1(tvd_write, FILE *, outfile) { /* * Next we write out the boot volume descriptor for the disc */ get_torito_desc(&gboot_desc); xfwrite(&gboot_desc, 1, 2048, outfile); last_extent_written ++; return 0; } struct output_fragment torito_desc = {NULL, oneblock_size, NULL, tvd_write};