xref: /openbsd/gnu/usr.sbin/mkhybrid/src/eltorito.c (revision 17df1aa7)
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  */
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 
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));
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  */
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