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