f8ec10b1c7046399c4adcbdf30afd51d5579d6be
[reactos.git] / reactos / sdk / tools / mkisofs / schilytools / mkisofs / boot.c
1 /* @(#)boot.c 1.28 16/10/23 Copyright 1999-2016 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)boot.c 1.28 16/10/23 Copyright 1999-2016 J. Schilling";
6 #endif
7 /*
8 * Support for generic boot (sector 0..16)
9 * and to boot Sun sparc and Sun x86 systems.
10 *
11 * Copyright (c) 1999-2016 J. Schilling
12 */
13 /*@@C@@*/
14
15 #include "mkisofs.h"
16 #include <schily/fcntl.h>
17 #include <schily/utypes.h>
18 #include <schily/intcvt.h>
19 #include <schily/schily.h>
20 #include "sunlabel.h"
21
22 extern int use_sunx86boot;
23
24 LOCAL struct sun_label cd_label;
25 LOCAL struct x86_label sx86_label;
26 LOCAL struct pc_part fdisk_part;
27 LOCAL char *boot_files[NDKMAP]; /* Change this for > 8 x86 parts */
28
29 LOCAL void init_sparc_label __PR((void));
30 LOCAL void init_sunx86_label __PR((void));
31 EXPORT int sparc_boot_label __PR((char *label));
32 EXPORT int sunx86_boot_label __PR((char *label));
33 EXPORT int scan_sparc_boot __PR((char *files));
34 EXPORT int scan_sunx86_boot __PR((char *files));
35 EXPORT int make_sun_label __PR((void));
36 EXPORT int make_sunx86_label __PR((void));
37 LOCAL void dup_sun_label __PR((int part));
38 LOCAL int sunboot_write __PR((FILE *outfile));
39 LOCAL int sunlabel_size __PR((UInt32_t starting_extent));
40 LOCAL int sunlabel_write __PR((FILE *outfile));
41 LOCAL int genboot_size __PR((UInt32_t starting_extent));
42 LOCAL int genboot_write __PR((FILE *outfile));
43
44 /*
45 * Set the virtual geometry in the disk label.
46 * If we like to make the geometry variable, we may change
47 * dkl_ncyl and dkl_pcyl later.
48 */
49 LOCAL void
50 init_sparc_label()
51 {
52 i_to_4_byte(cd_label.dkl_vtoc.v_version, V_VERSION);
53 i_to_2_byte(cd_label.dkl_vtoc.v_nparts, NDKMAP);
54 i_to_4_byte(cd_label.dkl_vtoc.v_sanity, VTOC_SANE);
55
56 i_to_2_byte(cd_label.dkl_rpm, CD_RPM);
57 i_to_2_byte(cd_label.dkl_pcyl, CD_PCYL);
58 i_to_2_byte(cd_label.dkl_apc, CD_APC);
59 i_to_2_byte(cd_label.dkl_intrlv, CD_INTRLV);
60 i_to_2_byte(cd_label.dkl_ncyl, CD_NCYL);
61 i_to_2_byte(cd_label.dkl_acyl, CD_ACYL);
62 i_to_2_byte(cd_label.dkl_nhead, CD_NHEAD);
63 i_to_2_byte(cd_label.dkl_nsect, CD_NSECT);
64
65 cd_label.dkl_magic[0] = DKL_MAGIC_0;
66 cd_label.dkl_magic[1] = DKL_MAGIC_1;
67 }
68
69 LOCAL void
70 init_sunx86_label()
71 {
72 li_to_4_byte(sx86_label.dkl_vtoc.v_sanity, VTOC_SANE);
73 li_to_4_byte(sx86_label.dkl_vtoc.v_version, V_VERSION);
74 li_to_2_byte(sx86_label.dkl_vtoc.v_sectorsz, 512);
75 li_to_2_byte(sx86_label.dkl_vtoc.v_nparts, NX86MAP);
76
77 li_to_4_byte(sx86_label.dkl_pcyl, CD_PCYL);
78 li_to_4_byte(sx86_label.dkl_ncyl, CD_NCYL);
79 li_to_2_byte(sx86_label.dkl_acyl, CD_ACYL);
80 li_to_2_byte(sx86_label.dkl_bcyl, 0);
81
82 li_to_4_byte(sx86_label.dkl_nhead, CD_NHEAD);
83 li_to_4_byte(sx86_label.dkl_nsect, CD_NSECT);
84 li_to_2_byte(sx86_label.dkl_intrlv, CD_INTRLV);
85 li_to_2_byte(sx86_label.dkl_skew, 0);
86 li_to_2_byte(sx86_label.dkl_apc, CD_APC);
87 li_to_2_byte(sx86_label.dkl_rpm, CD_RPM);
88
89 li_to_2_byte(sx86_label.dkl_write_reinstruct, 0);
90 li_to_2_byte(sx86_label.dkl_read_reinstruct, 0);
91
92 li_to_2_byte(sx86_label.dkl_magic, DKL_MAGIC);
93 }
94
95 /*
96 * For command line parser: set ASCII label.
97 */
98 EXPORT int
99 sparc_boot_label(label)
100 char *label;
101 {
102 strncpy(cd_label.dkl_ascilabel, label, 127);
103 cd_label.dkl_ascilabel[127] = '\0';
104 return (1);
105 }
106
107 EXPORT int
108 sunx86_boot_label(label)
109 char *label;
110 {
111 strncpy(sx86_label.dkl_vtoc.v_asciilabel, label, 127);
112 sx86_label.dkl_vtoc.v_asciilabel[127] = '\0';
113 return (1);
114 }
115
116 /*
117 * Parse the command line argument for boot images.
118 */
119 EXPORT int
120 scan_sparc_boot(files)
121 char *files;
122 {
123 char *p;
124 int i = 1;
125 struct stat statbuf;
126 int status;
127 extern int use_sparcboot;
128 extern int use_sunx86boot;
129
130 if (use_sunx86boot)
131 comerrno(EX_BAD,
132 _("-sparc-boot and -sunx86-boot are mutual exclusive.\n"));
133 use_sparcboot++;
134
135 init_sparc_label();
136
137 do {
138 if (i >= NDKMAP)
139 comerrno(EX_BAD, _("Too many boot partitions.\n"));
140 boot_files[i++] = files;
141 if ((p = strchr(files, ',')) != NULL)
142 *p++ = '\0';
143 files = p;
144 } while (p);
145
146 i_to_2_byte(cd_label.dkl_vtoc.v_part[0].p_tag, V_USR);
147 i_to_2_byte(cd_label.dkl_vtoc.v_part[0].p_flag, V_RONLY);
148 for (i = 0; i < NDKMAP; i++) {
149 p = boot_files[i];
150 if (p == NULL || *p == '\0')
151 continue;
152 if (strcmp(p, "...") == '\0')
153 break;
154
155 status = stat_filter(p, &statbuf);
156 if (status < 0 || access(p, R_OK) < 0)
157 comerr(_("Cannot access '%s'.\n"), p);
158
159 i_to_4_byte(cd_label.dkl_map[i].dkl_nblk,
160 roundup(statbuf.st_size, CD_CYLSIZE)/512);
161
162 i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_tag, V_ROOT);
163 i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_flag, V_RONLY);
164 }
165 return (1);
166 }
167
168 EXPORT int
169 scan_sunx86_boot(files)
170 char *files;
171 {
172 char *p;
173 int i = 0;
174 struct stat statbuf;
175 int status;
176 extern int use_sparcboot;
177 extern int use_sunx86boot;
178
179 if (use_sparcboot)
180 comerrno(EX_BAD,
181 _("-sparc-boot and -sunx86-boot are mutual exclusive.\n"));
182 use_sunx86boot++;
183
184
185 init_sunx86_label();
186
187 do {
188 if (i >= NDKMAP)
189 comerrno(EX_BAD, _("Too many boot partitions.\n"));
190 boot_files[i++] = files;
191 if ((p = strchr(files, ',')) != NULL)
192 *p++ = '\0';
193 files = p;
194 } while (p);
195
196 li_to_2_byte(sx86_label.dkl_vtoc.v_part[0].p_tag, V_ROOT); /* UFS */
197 li_to_2_byte(sx86_label.dkl_vtoc.v_part[0].p_flag, V_RONLY);
198 li_to_2_byte(sx86_label.dkl_vtoc.v_part[1].p_tag, V_USR); /* ISO */
199 li_to_2_byte(sx86_label.dkl_vtoc.v_part[1].p_flag, V_RONLY);
200 li_to_2_byte(sx86_label.dkl_vtoc.v_part[2].p_tag, 0); /* ALL */
201 li_to_2_byte(sx86_label.dkl_vtoc.v_part[2].p_flag, 0);
202 for (i = 0; i < NDKMAP; i++) {
203 p = boot_files[i];
204 if (p == NULL || *p == '\0')
205 continue;
206 if (i == 1 || i == 2) {
207 comerrno(EX_BAD,
208 _("Partition %d may not have a filename.\n"), i);
209 }
210
211 status = stat_filter(p, &statbuf);
212 if (status < 0 || access(p, R_OK) < 0)
213 comerr(_("Cannot access '%s'.\n"), p);
214
215 li_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_size,
216 roundup(statbuf.st_size, CD_CYLSIZE)/512);
217
218 if (i > 2) {
219 li_to_2_byte(sx86_label.dkl_vtoc.v_part[i].p_tag, V_USR);
220 li_to_2_byte(sx86_label.dkl_vtoc.v_part[i].p_flag, V_RONLY);
221 }
222 }
223 return (1);
224 }
225
226 /*
227 * Finish the Sun disk label and compute the size of the additional data.
228 */
229 EXPORT int
230 make_sun_label()
231 {
232 int last;
233 int cyl = 0;
234 int nblk;
235 int bsize;
236 int i;
237 char *p;
238
239 /*
240 * Compute the size of the padding for the iso9660 image
241 * to allow the next partition to start on a cylinder boundary.
242 */
243 last = roundup(last_extent, (CD_CYLSIZE/SECTOR_SIZE));
244
245 i_to_4_byte(cd_label.dkl_map[0].dkl_nblk, last*4);
246 bsize = 0;
247 for (i = 0; i < NDKMAP; i++) {
248 p = boot_files[i];
249 if (p != NULL && strcmp(p, "...") == '\0') {
250 dup_sun_label(i);
251 break;
252 }
253 if ((nblk = a_to_4_byte(cd_label.dkl_map[i].dkl_nblk)) == 0)
254 continue;
255
256 i_to_4_byte(cd_label.dkl_map[i].dkl_cylno, cyl);
257 cyl += nblk / (CD_CYLSIZE/512);
258 if (i > 0)
259 bsize += nblk;
260 }
261 bsize /= 4;
262 return (last-last_extent+bsize);
263 }
264
265 /*
266 * A typical Solaris boot/install CD from a Sun CD set looks
267 * this way:
268 *
269 * UFS Part 0 tag 2 flag 10 start 3839 size 1314560
270 * ISO Part 1 tag 4 flag 10 start 0 size 3839
271 * ALL Part 2 tag 0 flag 0 start 0 size 1318400
272 */
273 EXPORT int
274 make_sunx86_label()
275 {
276 int last;
277 int cyl = 0;
278 int nblk;
279 int bsize;
280 int i;
281 int partoff = 1; /* The offset of the Solaris 0x82 partition */
282
283 /*
284 * Compute the size of the padding for the iso9660 image
285 * to allow the next partition to start on a cylinder boundary.
286 */
287 last = roundup(last_extent, (CD_CYLSIZE/SECTOR_SIZE));
288
289 li_to_4_byte(sx86_label.dkl_vtoc.v_part[1].p_size, last*4);
290
291 /*
292 * Note that the Solaris fdisk partition with fdisk signature 0x82
293 * is created at fixed offset 1 sector == 512 Bytes by this
294 * implementation.
295 * We need subtract this partition offset from all absolute
296 * partition offsets in order to get offsets relative to the
297 * Solaris primary partition.
298 */
299 bsize = 0;
300 for (i = 0; i < NDKMAP; i++) {
301 if (i == 2) /* Never include the whole disk in */
302 continue; /* size/offset computations */
303
304 if ((nblk = la_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_size)) == 0)
305 continue;
306
307 li_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_start,
308 cyl*(CD_CYLSIZE/512)-partoff);
309 cyl += nblk / (CD_CYLSIZE/512);
310 if (i == 0 || i > 2)
311 bsize += nblk;
312 }
313 li_to_4_byte(sx86_label.dkl_vtoc.v_part[0].p_start, last*4-partoff);
314 li_to_4_byte(sx86_label.dkl_vtoc.v_part[1].p_start, 0);
315 li_to_4_byte(sx86_label.dkl_vtoc.v_part[1].p_size, last*4-partoff);
316 li_to_4_byte(sx86_label.dkl_vtoc.v_part[2].p_start, 0);
317 li_to_4_byte(sx86_label.dkl_vtoc.v_part[2].p_size, last*4+bsize);
318
319 fdisk_part.part[0].pr_status = STATUS_ACTIVE;
320 fdisk_part.part[0].pr_type = TYPE_SOLARIS;
321 li_to_4_byte(fdisk_part.part[0].pr_partoff, partoff);
322 li_to_4_byte(fdisk_part.part[0].pr_nsect, last*4+bsize-partoff);
323 fdisk_part.magic[0] = 0x55;
324 fdisk_part.magic[1] = 0xAA;
325
326 bsize /= 4;
327 return (last-last_extent+bsize);
328 }
329
330 /*
331 * Duplicate a partition of the Sun disk label until all partitions are filled up.
332 */
333 LOCAL void
334 dup_sun_label(part)
335 int part;
336 {
337 int cyl;
338 int nblk;
339 int i;
340
341
342 if (part < 1 || part >= NDKMAP)
343 part = 1;
344 cyl = a_to_4_byte(cd_label.dkl_map[part-1].dkl_cylno);
345 nblk = a_to_4_byte(cd_label.dkl_map[part-1].dkl_nblk);
346
347 for (i = part; i < NDKMAP; i++) {
348 i_to_4_byte(cd_label.dkl_map[i].dkl_cylno, cyl);
349 i_to_4_byte(cd_label.dkl_map[i].dkl_nblk, nblk);
350
351 i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_tag, V_ROOT);
352 i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_flag, V_RONLY);
353 }
354 }
355
356 /*
357 * Write out Sun boot partitions.
358 */
359 LOCAL int
360 sunboot_write(outfile)
361 FILE *outfile;
362 {
363 char buffer[SECTOR_SIZE];
364 int i;
365 int n;
366 int nblk;
367 int amt;
368 int f;
369 char *p;
370
371 memset(buffer, 0, sizeof (buffer));
372
373 /*
374 * Write padding to the iso9660 image to allow the
375 * boot partitions to start on a cylinder boundary.
376 */
377 amt = roundup(last_extent_written, (CD_CYLSIZE/SECTOR_SIZE)) - last_extent_written;
378 for (n = 0; n < amt; n++) {
379 xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
380 last_extent_written++;
381 }
382 if (use_sunx86boot)
383 i = 0;
384 else
385 i = 1;
386 for (; i < NDKMAP; i++) {
387 if (use_sunx86boot && (i == 1 || i == 2))
388 continue;
389 p = boot_files[i];
390 if (p == NULL || *p == '\0')
391 continue;
392 if (p != NULL && strcmp(p, "...") == '\0')
393 break;
394 if (use_sunx86boot) {
395 if ((nblk = la_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_size)) == 0)
396 continue;
397 } else {
398 if ((nblk = a_to_4_byte(cd_label.dkl_map[i].dkl_nblk)) == 0)
399 continue;
400 }
401 if ((f = open(boot_files[i], O_RDONLY| O_BINARY)) < 0)
402 comerr(_("Cannot open '%s'.\n"), boot_files[i]);
403
404 amt = nblk / 4;
405 for (n = 0; n < amt; n++) {
406 memset(buffer, 0, sizeof (buffer));
407 if (read(f, buffer, SECTOR_SIZE) < 0)
408 comerr(_("Read error on '%s'.\n"), boot_files[i]);
409 xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
410 last_extent_written++;
411 }
412 close(f);
413 }
414 fprintf(stderr, _("Total extents including %s boot = %u\n"),
415 use_sunx86boot ? "Solaris x86":"sparc",
416 last_extent_written - session_start);
417 return (0);
418 }
419
420 /*
421 * Do size management for the Sun disk label that is located in the first
422 * sector of a disk.
423 */
424 LOCAL int
425 sunlabel_size(starting_extent)
426 UInt32_t starting_extent;
427 {
428 if (last_extent != session_start)
429 comerrno(EX_BAD, _("Cannot create sparc boot on offset != 0.\n"));
430 last_extent++;
431 return (0);
432 }
433
434 /*
435 * Compute the checksum and write a Sun disk label to the first sector
436 * of the disk.
437 * If the -generic-boot option has been specified too, overlay the
438 * Sun disk label on the first 512 bytes of the generic boot code.
439 */
440 LOCAL int
441 sunlabel_write(outfile)
442 FILE *outfile;
443 {
444 char buffer[SECTOR_SIZE];
445 register char *p;
446 register short count = (512/2) - 1;
447 int f;
448
449 memset(buffer, 0, sizeof (buffer));
450 if (genboot_image) {
451 if ((f = open(genboot_image, O_RDONLY| O_BINARY)) < 0)
452 comerr(_("Cannot open '%s'.\n"), genboot_image);
453
454 if (read(f, buffer, SECTOR_SIZE) < 0)
455 comerr(_("Read error on '%s'.\n"), genboot_image);
456 close(f);
457 }
458
459 if (use_sunx86boot) {
460 if (sx86_label.dkl_vtoc.v_asciilabel[0] == '\0')
461 strcpy(sx86_label.dkl_vtoc.v_asciilabel, CD_X86LABEL);
462
463 p = (char *)&sx86_label;
464 sx86_label.dkl_cksum[0] = 0;
465 sx86_label.dkl_cksum[1] = 0;
466 while (count-- > 0) {
467 sx86_label.dkl_cksum[0] ^= *p++;
468 sx86_label.dkl_cksum[1] ^= *p++;
469 }
470 memcpy(&buffer[0x1BE], fdisk_part.part, sizeof (fdisk_part.part));
471 p = &buffer[510];
472 *p++ = 0x55;
473 *p = 0xAA;
474 memcpy(&buffer[1024], &sx86_label, 512);
475 } else {
476 /*
477 * If we don't already have a Sun disk label text
478 * set up the default.
479 */
480 if (cd_label.dkl_ascilabel[0] == '\0')
481 strcpy(cd_label.dkl_ascilabel, CD_DEFLABEL);
482
483 p = (char *)&cd_label;
484 cd_label.dkl_cksum[0] = 0;
485 cd_label.dkl_cksum[1] = 0;
486 while (count--) {
487 cd_label.dkl_cksum[0] ^= *p++;
488 cd_label.dkl_cksum[1] ^= *p++;
489 }
490 memcpy(buffer, &cd_label, 512);
491 }
492
493 xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
494 last_extent_written++;
495 return (0);
496 }
497
498 /*
499 * Do size management for the generic boot code on sectors 0..16.
500 */
501 LOCAL int
502 genboot_size(starting_extent)
503 UInt32_t starting_extent;
504 {
505 if (last_extent > (session_start + 1))
506 comerrno(EX_BAD, _("Cannot create generic boot on offset != 0.\n"));
507 last_extent = session_start + 16;
508 return (0);
509 }
510
511 /*
512 * Write the generic boot code to sectors 0..16.
513 * If there is a Sun disk label, start writing at sector 1.
514 */
515 LOCAL int
516 genboot_write(outfile)
517 FILE *outfile;
518 {
519 char buffer[SECTOR_SIZE];
520 int i;
521 int f;
522
523 if ((f = open(genboot_image, O_RDONLY| O_BINARY)) < 0)
524 comerr(_("Cannot open '%s'.\n"), genboot_image);
525
526 for (i = 0; i < 16; i++) {
527 memset(buffer, 0, sizeof (buffer));
528 if (read(f, buffer, SECTOR_SIZE) < 0)
529 comerr(_("Read error on '%s'.\n"), genboot_image);
530
531 if (i != 0 || last_extent_written == session_start) {
532 xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
533 last_extent_written++;
534 }
535 }
536 close(f);
537 return (0);
538 }
539
540 struct output_fragment sunboot_desc = {NULL, NULL, NULL, sunboot_write, "Sun Boot" };
541 struct output_fragment sunlabel_desc = {NULL, sunlabel_size, NULL, sunlabel_write, "Sun Disk Label" };
542 struct output_fragment genboot_desc = {NULL, genboot_size, NULL, genboot_write, "Generic Boot" };