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
48 static int tvd_write __PR((FILE * outfile));
49
50 /*
51 * Check for presence of boot catalog. If it does not exist then make it
52 */
FDECL1(init_boot_catalog,const char *,path)53 void 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
FDECL1(get_torito_desc,struct eltorito_boot_descriptor *,boot_desc)118 void 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 */
FDECL1(tvd_write,FILE *,outfile)305 static 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
316 struct output_fragment torito_desc = {NULL, oneblock_size, NULL, tvd_write};
317