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