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