123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- /*
- * 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};
|