summaryrefslogtreecommitdiff
path: root/genisoimage/eltorito.c
diff options
context:
space:
mode:
Diffstat (limited to 'genisoimage/eltorito.c')
-rw-r--r--genisoimage/eltorito.c716
1 files changed, 716 insertions, 0 deletions
diff --git a/genisoimage/eltorito.c b/genisoimage/eltorito.c
new file mode 100644
index 0000000..d52e17e
--- /dev/null
+++ b/genisoimage/eltorito.c
@@ -0,0 +1,716 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)eltorito.c 1.33 05/02/27 joerg */
+/*
+ * 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) 1999-2004 J. Schilling
+ *
+ * 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 2, 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include "genisoimage.h"
+#include <fctldefs.h>
+#include <utypes.h>
+#include <intcvt.h>
+#include "match.h"
+#include "diskmbr.h"
+#include "bootinfo.h"
+#include <schily.h>
+
+#undef MIN
+#define MIN(a, b) (((a) < (b))? (a): (b))
+
+static struct eltorito_validation_entry valid_desc;
+static struct eltorito_boot_descriptor gboot_desc;
+static struct disk_master_boot_record disk_mbr;
+static unsigned int bcat_de_flags;
+
+void init_boot_catalog(const char *path);
+void insert_boot_cat(void);
+static void get_torito_desc(struct eltorito_boot_descriptor *boot_desc);
+static void fill_boot_desc(struct eltorito_defaultboot_entry *boot_desc_entry,
+ struct eltorito_boot_entry_info *boot_entry);
+void get_boot_entry(void);
+void new_boot_entry(void);
+static int tvd_write(FILE *outfile);
+
+
+static char *bootcat_path; /* filename of boot catalog */
+/*
+ * Make sure any existing boot catalog is excluded
+ */
+void
+init_boot_catalog(const char *path)
+{
+#ifdef SORTING
+ struct eltorito_boot_entry_info * cbe;
+
+ for (cbe = first_boot_entry;
+ cbe != NULL;
+ cbe = cbe->next) {
+ char *p;
+
+ if (cbe->boot_image == NULL)
+ comerrno(EX_BAD, "Missing boot image name, use -eltorito-boot option.\n");
+ p = (char *) e_malloc(strlen(cbe->boot_image) + strlen(path) + 2);
+ strcpy(p, path);
+ if (p[strlen(p) - 1] != '/') {
+ strcat(p, "/");
+ }
+ strcat(p, cbe->boot_image);
+ add_sort_match(p, sort_matches(p, 1));
+ free(p);
+ }
+#endif
+ bootcat_path = (char *) e_malloc(strlen(boot_catalog) + strlen(path) + 2);
+ strcpy(bootcat_path, path);
+ if (bootcat_path[strlen(bootcat_path) - 1] != '/') {
+ strcat(bootcat_path, "/");
+ }
+ strcat(bootcat_path, boot_catalog);
+
+ /*
+ * we are going to create a virtual catalog file
+ * - so make sure any existing is excluded
+ */
+ add_match(bootcat_path);
+
+ /* flag the file as a memory file */
+ bcat_de_flags = MEMORY_FILE;
+
+ /* find out if we want to "hide" this file */
+ if (i_matches(boot_catalog) || i_matches(bootcat_path))
+ bcat_de_flags |= INHIBIT_ISO9660_ENTRY;
+
+ if (j_matches(boot_catalog) || j_matches(bootcat_path))
+ bcat_de_flags |= INHIBIT_JOLIET_ENTRY;
+
+}/* init_boot_catalog(... */
+
+/*
+ * Create a boot catalog file in memory - genisoimage already uses this type of
+ * file for the TRANS.TBL files. Therefore the boot catalog is set up in
+ * similar way
+ */
+void
+insert_boot_cat()
+{
+ struct directory_entry *de;
+ struct directory_entry *s_entry;
+ char *p1;
+ char *p2;
+ char *p3;
+ struct directory *this_dir;
+ struct directory *dir;
+ char *buffer;
+
+ init_fstatbuf();
+
+ buffer = (char *) e_malloc(SECTOR_SIZE);
+ memset(buffer, 0, SECTOR_SIZE);
+
+ /*
+ * try to find the directory that will contain the boot.cat file
+ * - not very neat, but I can't think of a better way
+ */
+ p1 = strdup(boot_catalog);
+
+ /* get dirname (p1) and basename (p2) of boot.cat */
+ if ((p2 = strrchr(p1, '/')) != NULL) {
+ *p2 = '\0';
+ p2++;
+
+ /* find the dirname directory entry */
+ de = search_tree_file(root, p1);
+ if (!de) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD,
+ "Uh oh, I cant find the boot catalog directory '%s'!\n",
+ p1);
+#else
+ fprintf(stderr,
+ "Uh oh, I cant find the boot catalog directory '%s'!\n",
+ p1);
+ exit(1);
+#endif
+ }
+ this_dir = 0;
+
+ /* get the basename (p3) of the directory */
+ if ((p3 = strrchr(p1, '/')) != NULL)
+ p3++;
+ else
+ p3 = p1;
+
+ /* find the correct sub-directory entry */
+ for (dir = de->filedir->subdir; dir; dir = dir->next)
+ if (!(strcmp(dir->de_name, p3)))
+ this_dir = dir;
+
+ if (this_dir == 0) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD,
+ "Uh oh, I cant find the boot catalog directory '%s'!\n",
+ p3);
+#else
+ fprintf(stderr,
+ "Uh oh, I cant find the boot catalog directory '%s'!\n",
+ p3);
+ exit(1);
+#endif
+ }
+ } else {
+ /* boot.cat is in the root directory */
+ this_dir = root;
+ p2 = p1;
+ }
+
+ /*
+ * make a directory entry in memory (using the same set up as for table
+ * entries
+ */
+ s_entry = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memset(s_entry, 0, sizeof (struct directory_entry));
+ s_entry->next = this_dir->contents;
+ this_dir->contents = s_entry;
+
+#ifdef SORTING
+ /* inherit any sort weight from parent directory */
+ s_entry->sort = this_dir->sort;
+ s_entry->sort += 2;
+
+ /* see if this entry should have a new weighting */
+ if (do_sort) {
+ s_entry->sort = sort_matches(bootcat_path, s_entry->sort);
+ }
+#endif /* SORTING */
+
+ s_entry->isorec.flags[0] = ISO_FILE;
+ s_entry->priority = 32768;
+ iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
+ s_entry->inode = TABLE_INODE;
+ s_entry->dev = (dev_t) UNCACHED_DEVICE;
+ set_723(s_entry->isorec.volume_sequence_number,
+ volume_sequence_number);
+ set_733((char *) s_entry->isorec.size, SECTOR_SIZE);
+ s_entry->size = SECTOR_SIZE;
+ s_entry->filedir = this_dir;
+ s_entry->name = strdup(p2);
+ iso9660_file_length(p2, s_entry, 0);
+
+ /* flag file as necessary */
+
+ /*
+ * If the current directory is hidden, then hide this entry
+ */
+ if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
+ bcat_de_flags |= INHIBIT_ISO9660_ENTRY;
+ if (this_dir->dir_flags & INHIBIT_JOLIET_ENTRY)
+ bcat_de_flags |= INHIBIT_JOLIET_ENTRY;
+
+ s_entry->de_flags = bcat_de_flags;
+
+ if ((use_XA || use_RockRidge) &&
+ !(bcat_de_flags & INHIBIT_ISO9660_ENTRY)) {
+ fstatbuf.st_mode = 0444 | S_IFREG;
+ fstatbuf.st_nlink = 1;
+ generate_xa_rr_attributes("",
+ p2, s_entry,
+ &fstatbuf, &fstatbuf, 0);
+ }
+ /*
+ * memory files are stored at s_entry->table
+ * - but this is also used for each s_entry to generate
+ * TRANS.TBL entries. So if we are generating tables,
+ * store the TRANS.TBL data here for the moment
+ */
+ if (generate_tables && !(bcat_de_flags & INHIBIT_ISO9660_ENTRY)) {
+ sprintf(buffer, "F\t%s\n", s_entry->name);
+
+ /* copy the TRANS.TBL entry info and clear the buffer */
+ s_entry->table = strdup(buffer);
+ memset(buffer, 0, SECTOR_SIZE);
+
+ /*
+ * store the (empty) file data in the
+ * unused s_entry->whole_name element for the time being
+ * - this will be transferred to s_entry->table after any
+ * TRANS.TBL processing later
+ */
+ s_entry->whole_name = buffer;
+ } else {
+ /* store the (empty) file data in the s_entry->table element */
+ s_entry->table = buffer;
+ s_entry->whole_name = NULL;
+ }
+}
+
+static void
+get_torito_desc(struct eltorito_boot_descriptor *boot_desc)
+{
+ int checksum;
+ unsigned char *checksum_ptr;
+ struct directory_entry *de2; /* Boot catalog */
+ int i;
+ int offset;
+ struct eltorito_defaultboot_entry boot_desc_record;
+
+ memset(boot_desc, 0, sizeof (*boot_desc));
+ boot_desc->type[0] = 0;
+ memcpy(boot_desc->id, 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
+ * - we already know where the boot catalog is
+ * - we created it above - but lets search for it anyway
+ * - good sanity check!
+ */
+ de2 = search_tree_file(root, boot_catalog);
+ if (!de2 || !(de2->de_flags & MEMORY_FILE)) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD, "Uh oh, I cant find the boot catalog '%s'!\n",
+ boot_catalog);
+#else
+ fprintf(stderr, "Uh oh, I cant find the boot catalog '%s'!\n",
+ boot_catalog);
+ exit(1);
+#endif
+ }
+ set_731(boot_desc->bootcat_ptr,
+ (unsigned int) get_733(de2->isorec.extent));
+
+ /*
+ * 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] = (char) 0x55;
+ valid_desc.key2[0] = (char) 0xAA;
+
+ /* compute the checksum */
+ checksum = 0;
+ checksum_ptr = (unsigned char *) &valid_desc;
+ /* Set checksum to 0 before computing checksum */
+ set_721(valid_desc.cksum, 0);
+ for (i = 0; i < (int)sizeof (valid_desc); i += 2) {
+ 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 write it to the virtual boot catalog */
+ memcpy(de2->table, &valid_desc, 32);
+
+ for (current_boot_entry = first_boot_entry, offset = sizeof (valid_desc);
+ current_boot_entry != NULL;
+ current_boot_entry = current_boot_entry->next,
+ offset += sizeof (boot_desc_record)) {
+
+ if (offset >= SECTOR_SIZE) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD,
+ "Too many El Torito boot entries\n");
+#else
+ fprintf(stderr,
+ "Too many El Torito boot entries\n");
+ exit(1);
+#endif
+ }
+ fill_boot_desc(&boot_desc_record, current_boot_entry);
+ memcpy(de2->table + offset, &boot_desc_record,
+ sizeof (boot_desc_record));
+ }
+}/* get_torito_desc(... */
+
+static void
+fill_boot_desc(struct eltorito_defaultboot_entry *boot_desc_entry,
+ struct eltorito_boot_entry_info *boot_entry)
+{
+ struct directory_entry *de; /* Boot file */
+ int bootmbr;
+ int i;
+ int nsectors;
+ int geosec;
+
+ if (!boot_desc_entry || !boot_entry)
+ return;
+
+ /* now adjust boot catalog lets find boot image first */
+ de = search_tree_file(root, boot_entry->boot_image);
+ if (!de) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD, "Uh oh, I cant find the boot image '%s' !\n",
+ boot_entry->boot_image);
+#else
+ fprintf(stderr, "Uh oh, I cant find the boot image '%s' !\n",
+ boot_entry->boot_image);
+ exit(1);
+#endif
+ }
+ /* now make the initial/default entry for boot catalog */
+ memset(boot_desc_entry, 0, sizeof (*boot_desc_entry));
+ boot_desc_entry->boot_id[0] = (char) boot_entry->not_bootable ?
+ EL_TORITO_NOT_BOOTABLE : EL_TORITO_BOOTABLE;
+
+ /* use default BIOS loadpnt */
+ set_721(boot_desc_entry->loadseg, boot_entry->load_addr);
+
+ /*
+ * figure out size of boot image in 512-byte sectors.
+ * However, round up to the nearest integral CD (2048-byte) sector.
+ * This is only used for no-emulation booting.
+ */
+ nsectors = boot_entry->load_size ? boot_entry->load_size :
+ ISO_BLOCKS(de->size) * (SECTOR_SIZE/512);
+
+ if (verbose > 0) {
+ fprintf(stderr,
+ "Size of boot image is %d sectors -> ", nsectors);
+ }
+
+ if (boot_entry->hard_disk_boot) {
+ /* sanity test hard disk boot image */
+ boot_desc_entry->boot_media[0] = EL_TORITO_MEDIA_HD;
+ if (verbose > 0)
+ fprintf(stderr, "Emulating a hard disk\n");
+
+ /* read MBR */
+ bootmbr = open(de->whole_name, O_RDONLY | O_BINARY);
+ if (bootmbr == -1) {
+#ifdef USE_LIBSCHILY
+ comerr("Error opening boot image '%s' for read.\n",
+ de->whole_name);
+#else
+ fprintf(stderr,
+ "Error opening boot image '%s' for read.\n",
+ de->whole_name);
+ perror("");
+ exit(1);
+#endif
+ }
+ if (read(bootmbr, &disk_mbr, sizeof (disk_mbr)) !=
+ sizeof (disk_mbr)) {
+#ifdef USE_LIBSCHILY
+ comerr("Error reading MBR from boot image '%s'.\n",
+ de->whole_name);
+#else
+ fprintf(stderr,
+ "Error reading MBR from boot image '%s'.\n",
+ de->whole_name);
+ exit(1);
+#endif
+ }
+ close(bootmbr);
+ if (la_to_u_2_byte(disk_mbr.magic) != MBR_MAGIC) {
+#ifdef USE_LIBSCHILY
+ errmsgno(EX_BAD,
+ "Warning: boot image '%s' MBR is not a boot sector.\n",
+ de->whole_name);
+#else
+ fprintf(stderr,
+ "Warning: boot image '%s' MBR is not a boot sector.\n",
+ de->whole_name);
+#endif
+ }
+ /* find partition type */
+ boot_desc_entry->sys_type[0] = PARTITION_UNUSED;
+ for (i = 0; i < PARTITION_COUNT; ++i) {
+ int s_cyl_sec;
+ int e_cyl_sec;
+
+ s_cyl_sec =
+ la_to_u_2_byte(disk_mbr.partition[i].s_cyl_sec);
+ e_cyl_sec =
+ la_to_u_2_byte(disk_mbr.partition[i].e_cyl_sec);
+
+ if (disk_mbr.partition[i].type != PARTITION_UNUSED) {
+ if (boot_desc_entry->sys_type[0] !=
+ PARTITION_UNUSED) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD,
+ "Boot image '%s' has multiple partitions.\n",
+ de->whole_name);
+#else
+ fprintf(stderr,
+ "Boot image '%s' has multiple partitions.\n",
+ de->whole_name);
+ exit(1);
+#endif
+ }
+ boot_desc_entry->sys_type[0] =
+ disk_mbr.partition[i].type;
+
+ /* a few simple sanity warnings */
+ if (!boot_entry->not_bootable &&
+ disk_mbr.partition[i].status !=
+ PARTITION_ACTIVE) {
+ fprintf(stderr,
+ "Warning: partition not marked active.\n");
+ }
+ if (MBR_CYLINDER(s_cyl_sec) != 0 ||
+ disk_mbr.partition[i].s_head != 1 ||
+ MBR_SECTOR(s_cyl_sec != 1)) {
+ fprintf(stderr,
+ "Warning: partition does not start at 0/1/1.\n");
+ }
+ geosec = (MBR_CYLINDER(e_cyl_sec) + 1) *
+ (disk_mbr.partition[i].e_head + 1) *
+ MBR_SECTOR(e_cyl_sec);
+ if (geosec != nsectors) {
+ fprintf(stderr,
+ "Warning: image size does not match geometry (%d)\n",
+ geosec);
+ }
+#ifdef DEBUG_TORITO
+ fprintf(stderr, "Partition start %u/%u/%u\n",
+ MBR_CYLINDER(s_cyl_sec),
+ disk_mbr.partition[i].s_head,
+ MBR_SECTOR(s_cyl_sec));
+ fprintf(stderr, "Partition end %u/%u/%u\n",
+ MBR_CYLINDER(e_cyl_sec),
+ disk_mbr.partition[i].e_head,
+ MBR_SECTOR(e_cyl_sec));
+#endif
+ }
+ }
+ if (boot_desc_entry->sys_type[0] == PARTITION_UNUSED) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD,
+ "Boot image '%s' has no partitions.\n",
+ de->whole_name);
+#else
+ fprintf(stderr,
+ "Boot image '%s' has no partitions.\n",
+ de->whole_name);
+ exit(1);
+#endif
+ }
+#ifdef DEBUG_TORITO
+ fprintf(stderr, "Partition type %u\n",
+ boot_desc_entry->sys_type[0]);
+#endif
+ /* load single boot sector, in this case the MBR */
+ nsectors = 1;
+
+ } else if (boot_entry->no_emul_boot) {
+ /*
+ * no emulation is a simple image boot of all the sectors
+ * in the boot image
+ */
+ boot_desc_entry->boot_media[0] = EL_TORITO_MEDIA_NOEMUL;
+ if (verbose > 0)
+ fprintf(stderr, "No emulation\n");
+
+ } else {
+ /* choose size of emulated floppy based on boot image size */
+ if (nsectors == 2880) {
+ boot_desc_entry->boot_media[0] = EL_TORITO_MEDIA_144FLOP;
+ if (verbose > 0)
+ fprintf(stderr, "Emulating a 1440 kB floppy\n");
+
+ } else if (nsectors == 5760) {
+ boot_desc_entry->boot_media[0] = EL_TORITO_MEDIA_288FLOP;
+ if (verbose > 0)
+ fprintf(stderr, "Emulating a 2880 kB floppy\n");
+
+ } else if (nsectors == 2400) {
+ boot_desc_entry->boot_media[0] = EL_TORITO_MEDIA_12FLOP;
+ if (verbose > 0)
+ fprintf(stderr, "Emulating a 1200 kB floppy\n");
+
+ } else {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD,
+ "Error - boot image '%s' has not an allowable size.\n",
+ de->whole_name);
+#else
+ fprintf(stderr,
+ "Error - boot image '%s' has not an allowable size.\n",
+ de->whole_name);
+ exit(1);
+#endif
+ }
+
+ /* load single boot sector for floppies */
+ nsectors = 1;
+ }
+
+ /* fill in boot image details */
+#ifdef DEBUG_TORITO
+ fprintf(stderr, "Boot %u sectors\n", nsectors);
+ fprintf(stderr, "Extent of boot images is %d\n",
+ get_733(de->isorec.extent));
+#endif
+ set_721(boot_desc_entry->nsect, (unsigned int) nsectors);
+ set_731(boot_desc_entry->bootoff,
+ (unsigned int) get_733(de->isorec.extent));
+
+
+ /* If the user has asked for it, patch the boot image */
+ if (boot_entry->boot_info_table) {
+ int bootimage;
+ unsigned int bi_checksum;
+ unsigned int total_len;
+ static char csum_buffer[SECTOR_SIZE];
+ int len;
+ struct genisoimage_boot_info bi_table;
+ bootimage = open(de->whole_name, O_RDWR | O_BINARY);
+ if (bootimage == -1) {
+#ifdef USE_LIBSCHILY
+ comerr(
+ "Error opening boot image file '%s' for update.\n",
+ de->whole_name);
+#else
+ fprintf(stderr,
+ "Error opening boot image file '%s' for update.\n",
+ de->whole_name);
+ perror("");
+ exit(1);
+#endif
+ }
+ /* Compute checksum of boot image, sans 64 bytes */
+ total_len = 0;
+ bi_checksum = 0;
+ while ((len = read(bootimage, csum_buffer, SECTOR_SIZE)) > 0) {
+ if (total_len & 3) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD,
+ "Odd alignment at non-end-of-file in boot image '%s'.\n",
+ de->whole_name);
+#else
+ fprintf(stderr,
+ "Odd alignment at non-end-of-file in boot image '%s'.\n",
+ de->whole_name);
+ exit(1);
+#endif
+ }
+ 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) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD,
+ "Boot image file '%s' changed underneath us!\n",
+ de->whole_name);
+#else
+ fprintf(stderr,
+ "Boot image file '%s' changed underneath us!\n",
+ de->whole_name);
+ exit(1);
+#endif
+ }
+ /* End of file, set position to byte 8 */
+ lseek(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.bi_pvd, session_start + 16);
+ set_731(bi_table.bi_file, de->starting_block);
+ set_731(bi_table.bi_length, de->size);
+ set_731(bi_table.bi_csum, bi_checksum);
+
+ write(bootimage, &bi_table, sizeof (bi_table)); /* FIXME: check return value */
+ close(bootimage);
+ }
+}/* fill_boot_desc(... */
+
+void
+get_boot_entry()
+{
+ if (current_boot_entry)
+ return;
+
+ current_boot_entry = (struct eltorito_boot_entry_info *)
+ e_malloc(sizeof (struct eltorito_boot_entry_info));
+ memset(current_boot_entry, 0, sizeof (*current_boot_entry));
+
+ if (!first_boot_entry) {
+ first_boot_entry = current_boot_entry;
+ last_boot_entry = current_boot_entry;
+ } else {
+ last_boot_entry->next = current_boot_entry;
+ last_boot_entry = current_boot_entry;
+ }
+}
+
+void
+new_boot_entry()
+{
+ current_boot_entry = NULL;
+}
+
+/*
+ * Function to write the EVD for the disc.
+ */
+static int
+tvd_write(FILE *outfile)
+{
+ /* check the boot image is not NULL */
+ if (!boot_image) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD, "No boot image specified.\n");
+#else
+ fprintf(stderr, "No boot image specified.\n");
+ exit(1);
+#endif
+ }
+ /* Next we write out the boot volume descriptor for the disc */
+ get_torito_desc(&gboot_desc);
+ jtwrite(&gboot_desc, SECTOR_SIZE, 1, 0, FALSE);
+ xfwrite(&gboot_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
+ last_extent_written++;
+ return (0);
+}
+
+struct output_fragment torito_desc = {NULL, oneblock_size, NULL, tvd_write, "Eltorito Volume Descriptor"};