eltorito.c revision 1.2
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
24static char rcsid[] ="$Id: eltorito.c,v 1.2 2004/06/22 22:58:06 tom Exp $";
25
26#include <stdio.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <unistd.h>
30#include <fcntl.h>
31#include <stdlib.h>
32
33#include "config.h"
34#include "mkisofs.h"
35#include "iso9660.h"
36
37/* used by Win32 for opening binary file - not used by Unix */
38#ifndef O_BINARY
39#define O_BINARY 0
40#endif /* O_BINARY */
41
42#undef MIN
43#define MIN(a, b) (((a) < (b))? (a): (b))
44
45static struct eltorito_validation_entry valid_desc;
46static struct eltorito_defaultboot_entry default_desc;
47static struct eltorito_boot_descriptor gboot_desc;
48
49static int tvd_write	__PR((FILE * outfile));
50
51/*
52 * Check for presence of boot catalog. If it does not exist then make it
53 */
54void FDECL1(init_boot_catalog, const char *, path)
55{
56
57    int		  bcat;
58    char		* bootpath;                /* filename of boot catalog */
59    char		* buf;
60    struct stat	  statbuf;
61
62    bootpath = (char *) e_malloc(strlen(boot_catalog)+strlen(path)+2);
63    strcpy(bootpath, path);
64    if (bootpath[strlen(bootpath)-1] != '/')
65    {
66	strcat(bootpath,"/");
67    }
68
69    strcat(bootpath, boot_catalog);
70
71    /*
72     * check for the file existing
73     */
74#ifdef DEBUG_TORITO
75    fprintf(stderr,"Looking for boot catalog file %s\n",bootpath);
76#endif
77
78    if (!stat_filter(bootpath, &statbuf))
79    {
80	/*
81	 * make sure its big enough to hold what we want
82	 */
83	if (statbuf.st_size == 2048)
84	{
85	    /*
86	     * printf("Boot catalog exists, so we do nothing\n");
87	     */
88	    free(bootpath);
89	    return;
90	}
91	else
92	{
93	    fprintf(stderr, "A boot catalog exists and appears corrupted.\n");
94	    fprintf(stderr, "Please check the following file: %s.\n",bootpath);
95	    fprintf(stderr, "This file must be removed before a bootable CD can be done.\n");
96	    free(bootpath);
97	    exit(1);
98	}
99    }
100
101    /*
102     * file does not exist, so we create it
103     * make it one CD sector long
104     */
105    bcat = open(bootpath, O_WRONLY | O_CREAT | O_BINARY, S_IROTH | S_IRGRP | S_IRWXU );
106    if (bcat == -1)
107    {
108	fprintf(stderr, "Error creating boot catalog, exiting...\n");
109	perror("");
110	exit(1);
111    }
112
113    buf = (char *) e_malloc( 2048 );
114    write(bcat, buf, 2048);
115    close(bcat);
116    free(bootpath);
117} /* init_boot_catalog(... */
118
119void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc)
120{
121    int				bootcat;
122    int				checksum;
123    unsigned char		      * checksum_ptr;
124    struct directory_entry      * de;
125    struct directory_entry      * de2;
126    int				i;
127    int				nsectors;
128
129    memset(boot_desc, 0, sizeof(*boot_desc));
130    boot_desc->id[0] = 0;
131    memcpy(boot_desc->id2, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
132    boot_desc->version[0] = 1;
133
134    memcpy(boot_desc->system_id, EL_TORITO_ID, sizeof(EL_TORITO_ID));
135
136    /*
137     * search from root of iso fs to find boot catalog
138     */
139    de2 = search_tree_file(root, boot_catalog);
140    if (!de2)
141    {
142	fprintf(stderr,"Uh oh, I cant find the boot catalog!\n");
143	exit(1);
144    }
145
146    set_731(boot_desc->bootcat_ptr,
147	    (unsigned int) get_733(de2->isorec.extent));
148
149    /*
150     * now adjust boot catalog
151     * lets find boot image first
152     */
153    de=search_tree_file(root, boot_image);
154    if (!de)
155    {
156	fprintf(stderr,"Uh oh, I cant find the boot image!\n");
157	exit(1);
158    }
159
160    /*
161     * we have the boot image, so write boot catalog information
162     * Next we write out the primary descriptor for the disc
163     */
164    memset(&valid_desc, 0, sizeof(valid_desc));
165    valid_desc.headerid[0] = 1;
166    valid_desc.arch[0] = EL_TORITO_ARCH_x86;
167
168    /*
169     * we'll shove start of publisher id into id field, may get truncated
170     * but who really reads this stuff!
171     */
172    if (publisher)
173        memcpy_max(valid_desc.id,  publisher, MIN(23, strlen(publisher)));
174
175    valid_desc.key1[0] = 0x55;
176    valid_desc.key2[0] = 0xAA;
177
178    /*
179     * compute the checksum
180     */
181    checksum=0;
182    checksum_ptr = (unsigned char *) &valid_desc;
183    for (i=0; i<sizeof(valid_desc); i+=2)
184    {
185	/*
186	 * skip adding in ckecksum word, since we dont have it yet!
187	 */
188	if (i == 28)
189	{
190	    continue;
191	}
192	checksum += (unsigned int)checksum_ptr[i];
193	checksum += ((unsigned int)checksum_ptr[i+1])*256;
194    }
195
196    /*
197     * now find out the real checksum
198     */
199    checksum = -checksum;
200    set_721(valid_desc.cksum, (unsigned int) checksum);
201
202    /*
203     * now make the initial/default entry for boot catalog
204     */
205    memset(&default_desc, 0, sizeof(default_desc));
206    default_desc.boot_id[0] = EL_TORITO_BOOTABLE;
207
208    /*
209     * use default BIOS loadpnt
210     */
211    set_721(default_desc.loadseg, 0);
212    default_desc.arch[0] = EL_TORITO_ARCH_x86;
213
214    /*
215     * figure out size of boot image in sectors, for now hard code to
216     * assume 512 bytes/sector on a bootable floppy
217     */
218    nsectors = ((de->size + 511) & ~(511))/512;
219#ifdef APPLE_HYB
220    /* NON-HFS change */
221    if (verbose > 0 )
222#endif /* APPLE_HYB */
223	fprintf(stderr, "\nSize of boot image is %d sectors -> ", nsectors);
224
225    /*
226     * choose size of emulated floppy based on boot image size
227     */
228    if (nsectors == 2880 )
229    {
230	default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP;
231#ifdef APPLE_HYB
232	/* NON-HFS change */
233	if (verbose > 0 )
234#endif /* APPLE_HYB */
235	    fprintf(stderr, "Emulating a 1.44 meg floppy\n");
236    }
237    else if (nsectors == 5760 )
238    {
239	default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP;
240#ifdef APPLE_HYB
241	/* NON-HFS change */
242	if (verbose > 0 )
243#endif /* APPLE_HYB */
244	    fprintf(stderr,"Emulating a 2.88 meg floppy\n");
245    }
246    else if (nsectors == 2400 )
247    {
248	default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP;
249#ifdef APPLE_HYB
250	/* NON-HFS change */
251	if (verbose > 0 )
252#endif /* APPLE_HYB */
253	    fprintf(stderr,"Emulating a 1.2 meg floppy\n");
254    }
255    else if (nsectors == 4 )
256    {
257	default_desc.boot_media[0] = EL_TORITO_MEDIA_NOEMUL;
258#ifdef APPLE_HYB
259	/* NON-HFS change */
260	if (verbose > 0 )
261#endif /* APPLE_HYB */
262	    fprintf(stderr,"No-emulation CD boot sector\n");
263    }
264    else
265    {
266	fprintf(stderr,"\nError - boot image is not the an allowable size.\n");
267	exit(1);
268    }
269
270
271    /*
272     * FOR NOW LOAD 1 SECTOR, JUST LIKE FLOPPY BOOT, unless it's no-emulation
273     * boot.
274     */
275    if (default_desc.boot_media[0] != EL_TORITO_MEDIA_NOEMUL)
276        nsectors = 1;
277    set_721(default_desc.nsect, (unsigned int) nsectors );
278#ifdef DEBUG_TORITO
279    fprintf(stderr,"Extent of boot images is %d\n",get_733(de->isorec.extent));
280#endif
281    set_731(default_desc.bootoff,
282	    (unsigned int) get_733(de->isorec.extent));
283
284    /*
285     * now write it to disk
286     */
287    bootcat = open(de2->whole_name, O_RDWR | O_BINARY);
288    if (bootcat == -1)
289    {
290	fprintf(stderr,"Error opening boot catalog for update.\n");
291	perror("");
292	exit(1);
293    }
294
295    /*
296     * write out
297     */
298    write(bootcat, &valid_desc, 32);
299    write(bootcat, &default_desc, 32);
300    close(bootcat);
301} /* get_torito_desc(... */
302
303/*
304 * Function to write the EVD for the disc.
305 */
306static int FDECL1(tvd_write, FILE *, outfile)
307{
308  /*
309   * Next we write out the boot volume descriptor for the disc
310   */
311  get_torito_desc(&gboot_desc);
312  xfwrite(&gboot_desc, 1, 2048, outfile);
313  last_extent_written ++;
314  return 0;
315}
316
317struct output_fragment torito_desc    = {NULL, oneblock_size, NULL,     tvd_write};
318