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