eltorito.c
上传用户:xiejiait
上传日期:2007-01-06
资源大小:881k
文件大小:16k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*
  2.  * Program eltorito.c - Handle El Torito specific extensions to iso9660.
  3.  * 
  4.    Written by Michael Fulbright <msf@redhat.com> (1996).
  5.    Copyright 1996 RedHat Software, Incorporated
  6.    This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */
  17. static char rcsid[] ="$Id: eltorito.c,v 1.13 1999/03/02 03:41:25 eric Exp $";
  18. #include "config.h"
  19. #include <stdio.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <unistd.h>
  23. #include <stdlib.h>
  24. #include <fctldefs.h>
  25. #include "mkisofs.h"
  26. #include "match.h"
  27. #include "iso9660.h"
  28. #include "diskmbr.h"
  29. #include "bootinfo.h"
  30. #ifdef USE_LIBSCHILY
  31. #include <standard.h>
  32. #endif
  33. #include <utypes.h>
  34. #include <intcvt.h>
  35. #undef MIN
  36. #define MIN(a, b) (((a) < (b))? (a): (b))
  37. static struct eltorito_validation_entry valid_desc;
  38. static struct eltorito_defaultboot_entry default_desc;
  39. static struct eltorito_boot_descriptor gboot_desc;
  40. static struct disk_master_boot_record disk_mbr;
  41. static int tvd_write __PR((FILE * outfile));
  42. static unsigned int bcat_de_flags;
  43. /*
  44.  * Make sure any existing boot catalog is excluded
  45.  */
  46. void FDECL1(init_boot_catalog, const char *, path)
  47. {
  48.     char * bootpath;                /* filename of boot catalog */
  49.     
  50.     bootpath = (char *) e_malloc(strlen(boot_catalog)+strlen(path)+2);
  51.     strcpy(bootpath, path);
  52.     if (bootpath[strlen(bootpath)-1] != '/') 
  53.     {
  54. strcat(bootpath,"/");
  55.     }
  56.     strcat(bootpath, boot_catalog);
  57.     
  58.     /* we are going to create a virtual catalog file - so make sure any
  59.        existing is excluded */
  60.     add_match(bootpath);
  61.     /* flag the file as a memory file */
  62.     bcat_de_flags = MEMORY_FILE;
  63.     /* find out if we want to "hide" this file */
  64.     if (i_matches(boot_catalog) || i_matches(bootpath))
  65. bcat_de_flags |= INHIBIT_ISO9660_ENTRY;
  66.     if (j_matches(boot_catalog) || j_matches(bootpath))
  67. bcat_de_flags |= INHIBIT_JOLIET_ENTRY;
  68.     free(bootpath);
  69. } /* init_boot_catalog(... */
  70. /*
  71.  * Create a boot catalog file in memory - mkisofs already uses this type of
  72.  * file for the TRANS.TBL files. Therefore the boot catalog is set up in
  73.  * similar way 
  74.  */
  75. void insert_boot_cat()
  76. {
  77.     struct directory_entry * de, * s_entry;
  78.     char  * p1, * p2, *p3;
  79.     struct directory * this_dir, * dir;
  80.     char * buffer;
  81.     init_fstatbuf();
  82.     buffer = (char *) e_malloc( SECTOR_SIZE );
  83.     memset(buffer, 0, SECTOR_SIZE);
  84.     /* try to find the directory that will contain the boot.cat file
  85.        - not very neat, but I can't think of a better way */
  86.     p1 = strdup(boot_catalog);
  87.     /* get dirname (p1) and basename (p2) of boot.cat */
  88.     if ((p2 = strrchr(p1, '/')) != NULL) {
  89. *p2 = '';
  90. p2++;
  91. /* find the dirname directory entry */
  92. de = search_tree_file(root, p1);
  93. if (!de) 
  94. {
  95. #ifdef USE_LIBSCHILY
  96.     comerrno(EX_BAD, "Uh oh, I cant find the boot catalog directory '%s'!n", p1);
  97. #else
  98.     fprintf(stderr,"Uh oh, I cant find the boot catalog directory '%s'!n", p1);
  99.     exit(1);
  100. #endif
  101. }
  102. this_dir = 0;
  103. /* get the basename (p3) of the directory */
  104. if ((p3 = strrchr(p1, '/')) != NULL)
  105.     p3++;
  106. else
  107.     p3 = p1;
  108. /* find the correct sub-directory entry */
  109. for (dir = de->filedir->subdir; dir; dir = dir->next)
  110.     if (!(strcmp(dir->de_name, p3)))
  111. this_dir = dir;
  112. if (this_dir == 0 ) {
  113. #ifdef USE_LIBSCHILY
  114.     comerrno(EX_BAD, "Uh oh, I cant find the boot catalog directory '%s'!n", p3);
  115. #else
  116.     fprintf(stderr,"Uh oh, I cant find the boot catalog directory '%s'!n", p3);
  117.     exit(1);
  118. #endif
  119. }
  120.     } else {
  121. /* boot.cat is in the root directory */
  122. this_dir = root;
  123. p2 = p1;
  124.     }
  125.     /* make a directory entry in memory (using the same set up as for
  126.        table entries */
  127.     s_entry = (struct directory_entry *) 
  128. e_malloc(sizeof (struct directory_entry));
  129.     memset(s_entry, 0, sizeof(struct directory_entry));
  130.     s_entry->next = this_dir->contents;
  131.     this_dir->contents = s_entry;
  132.       
  133.     s_entry->isorec.flags[0] = 0;
  134.     s_entry->priority = 32768;
  135.     iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
  136.     s_entry->inode = TABLE_INODE;
  137.     s_entry->dev = (dev_t) UNCACHED_DEVICE;
  138.     set_723(s_entry->isorec.volume_sequence_number, volume_sequence_number);
  139.     set_733((char *) s_entry->isorec.size, SECTOR_SIZE);
  140.     s_entry->size = SECTOR_SIZE;
  141.     s_entry->filedir = this_dir;
  142.     s_entry->name = strdup(p2);
  143.     iso9660_file_length  (p2, s_entry, 0);
  144.     /* flag file as necessary */
  145.     s_entry->de_flags = bcat_de_flags;
  146.     if(use_RockRidge && !(bcat_de_flags & INHIBIT_ISO9660_ENTRY)) {
  147.   fstatbuf.st_mode = 0444 | S_IFREG;
  148.   fstatbuf.st_nlink = 1;
  149.   generate_rock_ridge_attributes("",
  150.  p2, s_entry,
  151.  &fstatbuf, &fstatbuf, 0);
  152.     }
  153.     /* memory files are stored at s_entry->table - but this is also
  154.        used for each s_entry to generate TRANS.TBL entries. So if we are
  155.        generating tables, store the TRANS.TBL data here for the moment */
  156.     if (generate_tables && !(bcat_de_flags & INHIBIT_ISO9660_ENTRY)) {
  157. sprintf(buffer,"Ft%sn",s_entry->name);
  158. /* copy the TRANS.TBL entry info and clear the buffer */
  159. s_entry->table = strdup(buffer);
  160. memset(buffer, 0, SECTOR_SIZE);
  161. /* store the (empty) file data in the unused s_entry->whole_name
  162.    element for the time being - this will be transferred to
  163.    s_entry->table after any TRANS.TBL processing later */
  164. s_entry->whole_name = buffer;
  165.     } else {
  166. /* store the (empty) file data in the s_entry->table element */
  167. s_entry->table = buffer;
  168. s_entry->whole_name = NULL;
  169.     }
  170. }
  171. void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc)
  172. {
  173.     int bootmbr;
  174.     int checksum;
  175.     unsigned char       * checksum_ptr;
  176.     struct directory_entry      * de;  /* Boot file */
  177.     struct directory_entry      * de2; /* Boot catalog */
  178.     int i;
  179.     int nsectors;
  180.     int geosec;
  181.     
  182.     memset(boot_desc, 0, sizeof(*boot_desc));
  183.     boot_desc->type[0] = 0;
  184.     memcpy(boot_desc->id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
  185.     boot_desc->version[0] = 1;
  186.     
  187.     memcpy(boot_desc->system_id, EL_TORITO_ID, sizeof(EL_TORITO_ID));
  188.     
  189.     /*
  190.      * search from root of iso fs to find boot catalog - we already know
  191.      * where the boot catalog is - we created it above - but lets search
  192.      * for it anyway - good sanity check!
  193.      */
  194.     de2 = search_tree_file(root, boot_catalog);
  195.     if (!de2 || !(de2->de_flags & MEMORY_FILE)) 
  196.     {
  197. #ifdef USE_LIBSCHILY
  198. comerrno(EX_BAD, "Uh oh, I cant find the boot catalog '%s'!n", boot_catalog);
  199. #else
  200. fprintf(stderr,"Uh oh, I cant find the boot catalog '%s'!n", boot_catalog);
  201. exit(1);
  202. #endif
  203.     }
  204.     
  205.     set_731(boot_desc->bootcat_ptr,
  206.     (unsigned int) get_733(de2->isorec.extent));
  207.     
  208.     /* 
  209.      * now adjust boot catalog
  210.      * lets find boot image first 
  211.      */
  212.     de=search_tree_file(root, boot_image);
  213.     if (!de) 
  214.     {
  215. #ifdef USE_LIBSCHILY
  216. comerrno(EX_BAD, "Uh oh, I cant find the boot image '%s' !n", boot_image);
  217. #else
  218. fprintf(stderr,"Uh oh, I cant find the boot image '%s' !n", boot_image);
  219. exit(1);
  220. #endif
  221.     } 
  222.     
  223.     /* 
  224.      * we have the boot image, so write boot catalog information
  225.      * Next we write out the primary descriptor for the disc 
  226.      */
  227.     memset(&valid_desc, 0, sizeof(valid_desc));
  228.     valid_desc.headerid[0] = 1;
  229.     valid_desc.arch[0] = EL_TORITO_ARCH_x86;
  230.     
  231.     /*
  232.      * we'll shove start of publisher id into id field, may get truncated
  233.      * but who really reads this stuff!
  234.      */
  235.     if (publisher)
  236.         memcpy_max(valid_desc.id,  publisher, MIN(23, strlen(publisher)));
  237.     
  238.     valid_desc.key1[0] = (char)0x55;
  239.     valid_desc.key2[0] = (char)0xAA;
  240.     
  241.     /*
  242.      * compute the checksum 
  243.      */
  244.     checksum=0;
  245.     checksum_ptr = (unsigned char *) &valid_desc;
  246.     /* Set checksum to 0 before computing checksum */
  247.     set_721(valid_desc.cksum, 0);
  248.     for (i=0; i<sizeof(valid_desc); i+=2) 
  249.     {
  250. checksum += (unsigned int)checksum_ptr[i];
  251. checksum += ((unsigned int)checksum_ptr[i+1])*256;
  252.     }
  253.     
  254.     /* 
  255.      * now find out the real checksum 
  256.      */
  257.     checksum = -checksum;
  258.     set_721(valid_desc.cksum, (unsigned int) checksum);
  259.     
  260.     /*
  261.      * now make the initial/default entry for boot catalog 
  262.      */
  263.     memset(&default_desc, 0, sizeof(default_desc));
  264.     default_desc.boot_id[0] = (char)not_bootable ? EL_TORITO_NOT_BOOTABLE : EL_TORITO_BOOTABLE;
  265.     
  266.     /*
  267.      * use default BIOS loadpnt
  268.      */ 
  269.     set_721(default_desc.loadseg, load_addr);
  270.     
  271.     /*
  272.      * figure out size of boot image in 512-byte sectors.  However,
  273.      * round up to the nearest integral CD (2048-byte) sector.
  274.      * This is only used for no-emulation booting.
  275.      */
  276.     nsectors = load_size ? load_size : ((de->size + 2047)/2048) * 4;
  277.     fprintf(stderr, "nSize of boot image is %d sectors -> ", nsectors); 
  278.     
  279.     if (hard_disk_boot) {
  280. /*
  281.  * sanity test hard disk boot image
  282.  */
  283. default_desc.boot_media[0] = EL_TORITO_MEDIA_HD;
  284. fprintf(stderr, "Emulating a hard diskn");
  285. /*
  286.  * read MBR
  287.  */
  288. bootmbr = open(de->whole_name, O_RDONLY | O_BINARY);
  289. if (bootmbr == -1) {
  290. #ifdef USE_LIBSCHILY
  291.     comerr("Error opening boot image '%s' for read.n", de->whole_name);
  292. #else
  293.     fprintf(stderr,"Error opening boot image '%s' for read.n", de->whole_name);
  294.     perror("");
  295.     exit(1);
  296. #endif
  297. }
  298. if(read(bootmbr, &disk_mbr, sizeof(disk_mbr)) != sizeof(disk_mbr)) {
  299. #ifdef USE_LIBSCHILY
  300.     comerr("Error reading MBR from boot image '%s'.n", de->whole_name);
  301. #else
  302.     fprintf(stderr,"Error reading MBR from boot image '%s'.n", de->whole_name);
  303.     exit(1);
  304. #endif
  305. }
  306. close(bootmbr);
  307. if(la_to_u_2_byte(disk_mbr.magic) != MBR_MAGIC) {
  308. #ifdef USE_LIBSCHILY
  309.     errmsgno(EX_BAD, "Warning: boot image '%s' MBR is not a boot sector.n", de->whole_name);
  310. #else
  311.     fprintf(stderr, "Warning: boot image '%s' MBR is not a boot sector.n", de->whole_name);
  312. #endif
  313. }
  314. /*
  315.  * find partition type
  316.  */
  317. default_desc.sys_type[0] = PARTITION_UNUSED;
  318. for(i = 0; i < PARTITION_COUNT; ++i) {
  319. int s_cyl_sec;
  320. int e_cyl_sec;
  321. s_cyl_sec = la_to_u_2_byte(disk_mbr.partition[i].s_cyl_sec);
  322. e_cyl_sec = la_to_u_2_byte(disk_mbr.partition[i].e_cyl_sec);
  323.             if(disk_mbr.partition[i].type != PARTITION_UNUSED) {
  324.         if(default_desc.sys_type[0] != PARTITION_UNUSED) {
  325. #ifdef USE_LIBSCHILY
  326.     comerrno(EX_BAD, "Boot image '%s' has multiple partitions.n", de->whole_name);
  327. #else
  328.     fprintf(stderr, "Boot image '%s' has multiple partitions.n", de->whole_name);
  329.     exit(1);
  330. #endif
  331. }
  332. default_desc.sys_type[0] = disk_mbr.partition[i].type;
  333. /*
  334.  * a few simple sanity warnings
  335.  */
  336. if(!not_bootable && disk_mbr.partition[i].status != PARTITION_ACTIVE) {
  337.     fprintf(stderr, "Warning: partition not marked active.n");
  338. }
  339. if(MBR_CYLINDER(s_cyl_sec) != 0 ||
  340.     disk_mbr.partition[i].s_head != 1 ||
  341.     MBR_SECTOR(s_cyl_sec != 1)) {
  342.             fprintf(stderr, "Warning: partition does not start at 0/1/1.n");
  343. }
  344. geosec = (MBR_CYLINDER(e_cyl_sec) + 1) *
  345.     (disk_mbr.partition[i].e_head + 1) *
  346.     MBR_SECTOR(e_cyl_sec);
  347. if(geosec != nsectors) {
  348.     fprintf(stderr, "Warning: image size does not match geometry (%d)n",
  349.         geosec);
  350. }
  351. #ifdef DEBUG_TORITO
  352. fprintf(stderr, "Partition start %u/%u/%un",
  353.     MBR_CYLINDER(s_cyl_sec),
  354.     disk_mbr.partition[i].s_head,
  355.     MBR_SECTOR(s_cyl_sec));
  356. fprintf(stderr, "Partition end %u/%u/%un",
  357.     MBR_CYLINDER(e_cyl_sec),
  358.     disk_mbr.partition[i].e_head,
  359.     MBR_SECTOR(e_cyl_sec));
  360. #endif
  361.     }
  362. }
  363. if(default_desc.sys_type[0] == PARTITION_UNUSED) {
  364. #ifdef USE_LIBSCHILY
  365.     comerrno(EX_BAD, "Boot image '%s' has no partitions.n", de->whole_name);
  366. #else
  367.     fprintf(stderr, "Boot image '%s' has no partitions.n", de->whole_name);
  368.     exit(1);
  369. #endif
  370. }
  371. #ifdef DEBUG_TORITO
  372. fprintf(stderr, "Partition type %un", default_desc.sys_type[0]);
  373. #endif
  374. /*
  375.  * load single boot sector, in this case the MBR
  376.  */
  377. nsectors = 1;
  378.     } else if(no_emul_boot) {
  379. /*
  380.  *  no emulation is a simple image boot of all the sectors in the boot image
  381.  */
  382. default_desc.boot_media[0] = EL_TORITO_MEDIA_NOEMUL;
  383.      fprintf(stderr,"No emulationn");
  384.     } else {
  385. /*
  386.  * choose size of emulated floppy based on boot image size 
  387.  */
  388. if (nsectors == 2880 ) 
  389. {
  390.     default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP;
  391.     fprintf(stderr, "Emulating a 1.44 meg floppyn");
  392. } else if (nsectors == 5760 ) {
  393.     default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP;
  394.     fprintf(stderr,"Emulating a 2.88 meg floppyn");
  395. } else if (nsectors == 2400 ) {
  396.     default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP;
  397.     fprintf(stderr,"Emulating a 1.2 meg floppyn");
  398. } else {
  399. #ifdef USE_LIBSCHILY
  400.     comerrno(EX_BAD, "Error - boot image '%s' is not the an allowable size.n", de->whole_name);
  401. #else
  402.     fprintf(stderr,"Error - boot image '%s' is not the an allowable size.n", de->whole_name);
  403.     exit(1);
  404. #endif
  405. }
  406. /*
  407.  * load single boot sector for floppies
  408.  */
  409. nsectors = 1;
  410.     }
  411.     
  412.     /*
  413.      * fill in boot image details
  414.      */
  415. #ifdef DEBUG_TORITO
  416.     fprintf(stderr,"Boot %u sectorsn",nsectors);
  417.     fprintf(stderr,"Extent of boot images is %dn",get_733(de->isorec.extent));
  418. #endif
  419.     set_721(default_desc.nsect, (unsigned int) nsectors );
  420.     set_731(default_desc.bootoff, 
  421.     (unsigned int) get_733(de->isorec.extent));
  422.     
  423.     /*
  424.      * now write it to the virtual boot catalog
  425.      */
  426.     memcpy(de2->table, &valid_desc, 32);
  427.     memcpy(de2->table + 32, &default_desc, 32);
  428.     /*
  429.      * If the user has asked for it, patch the boot image
  430.      */
  431.     if ( boot_info_table ) {
  432.       int bootimage;
  433.       unsigned int bi_checksum, total_len;
  434.       static char csum_buffer[2048];
  435.       int len;
  436.       struct mkisofs_boot_info bi_table;
  437.       bootimage = open(de->whole_name, O_RDWR | O_BINARY);
  438.       if ( bootimage == -1 ) {
  439. #ifdef USE_LIBSCHILY
  440. comerr("Error opening boot image file '%s' for update.n", de->whole_name);
  441. #else
  442. fprintf(stderr,"Error opening boot image file '%s' for update.n", de->whole_name);
  443. perror("");
  444. exit(1);
  445. #endif
  446.       }
  447.       /* Compute checksum of boot image, sans 64 bytes */
  448.       total_len = 0;  bi_checksum = 0;
  449.       while ( (len = read(bootimage, csum_buffer, 2048)) > 0 ) {
  450. if ( total_len & 3 ) {
  451. #ifdef USE_LIBSCHILY
  452.   comerrno(EX_BAD, "Odd alignment at non-end-of-file in boot image '%s'.n", de->whole_name);
  453. #else
  454.   fprintf(stderr, "Odd alignment at non-end-of-file in boot image '%s'.n", de->whole_name);
  455.   exit(1);
  456. #endif
  457. }
  458. if ( total_len < 64 )
  459.   memset(csum_buffer, 0, 64-total_len);
  460. if ( len < 2048 )
  461.   memset(csum_buffer+len, 0, 2048-len);
  462. for ( i = 0 ; i < 2048 ; i += 4 )
  463.   bi_checksum += get_731(&csum_buffer[i]);
  464. total_len += len;
  465.       }
  466.       if ( total_len != de->size ) {
  467. #ifdef USE_LIBSCHILY
  468. comerrno(EX_BAD, "Boot image file '%s' changed underneath us!n", de->whole_name);
  469. #else
  470. fprintf(stderr, "Boot image file '%s' changed underneath us!n", de->whole_name);
  471. exit(1);
  472. #endif
  473.       }
  474.       /* End of file, set position to byte 8 */
  475.       lseek(bootimage, 8, SEEK_SET);
  476.       memset(&bi_table, 0, sizeof(bi_table));
  477.       /* Is it always safe to assume PVD is at session_start+16? */
  478.       set_731(bi_table.bi_pvd,    session_start+16);
  479.       set_731(bi_table.bi_file,   de->starting_block);
  480.       set_731(bi_table.bi_length, de->size);
  481.       set_731(bi_table.bi_csum,   bi_checksum);
  482.       
  483.       write(bootimage, &bi_table, sizeof(bi_table));
  484.       close(bootimage);
  485.     }
  486. } /* get_torito_desc(... */
  487. /*
  488.  * Function to write the EVD for the disc.
  489.  */
  490. static int FDECL1(tvd_write, FILE *, outfile)
  491. {
  492.   /*
  493.    * check the boot image is not NULL
  494.    */
  495.   if(!boot_image)
  496.   {
  497. #ifdef USE_LIBSCHILY
  498. comerrno(EX_BAD, "No boot image specified.n");
  499. #else
  500. fprintf(stderr,"No boot image specified.n");
  501. exit(1);
  502. #endif
  503.   }
  504.   /*
  505.    * Next we write out the boot volume descriptor for the disc 
  506.    */
  507.   get_torito_desc(&gboot_desc);
  508.   xfwrite(&gboot_desc, 1, SECTOR_SIZE, outfile);
  509.   last_extent_written ++;
  510.   return 0;
  511. }
  512. struct output_fragment torito_desc    = {NULL, oneblock_size, NULL,     tvd_write};