xref: /openbsd/gnu/usr.sbin/mkhybrid/src/eltorito.c (revision ca3aaadb)
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 
44 static struct eltorito_validation_entry valid_desc;
45 static struct eltorito_defaultboot_entry default_desc;
46 static struct eltorito_boot_descriptor gboot_desc;
47 static struct eltorito_sectionheader_entry shdr_desc;
48 static struct eltorito_defaultboot_entry efi_desc;
49 
50 static int tvd_write	__PR((FILE * outfile));
51 
52 /*
53  * Check for presence of boot catalog. If it does not exist then make it
54  */
FDECL1(init_boot_catalog,const char *,path)55 void 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 
FDECL1(get_torito_desc,struct eltorito_boot_descriptor *,boot_desc)120 void 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  */
FDECL1(tvd_write,FILE *,outfile)343 static 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 
354 struct output_fragment torito_desc    = {NULL, oneblock_size, NULL,     tvd_write};
355