2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)boot.c 1.13 04/02/22 Copyright 1999-2003 J. Schilling */
15 * Support for generic boot (sector 0..16)
16 * and to boot Sun sparc and Sun x86 systems.
18 * Copyright (c) 1999-2003 J. Schilling
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License version 2
23 * as published by the Free Software Foundation.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License along with
31 * this program; see the file COPYING. If not, write to the Free Software
32 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36 #include "genisoimage.h"
43 extern int use_sunx86boot;
45 static struct sun_label cd_label;
46 static struct x86_label sx86_label;
47 static struct pc_part fdisk_part;
48 static char *boot_files[NDKMAP]; /* Change this for > 8 x86 parts */
50 static void init_sparc_label(void);
51 static void init_sunx86_label(void);
52 void sparc_boot_label(char *label);
53 void sunx86_boot_label(char *label);
54 void scan_sparc_boot(char *files);
55 void scan_sunx86_boot(char *files);
56 int make_sun_label(void);
57 int make_sunx86_label(void);
58 static void dup_sun_label(int part);
59 static int sunboot_write(FILE *outfile);
60 static int sunlabel_size(int starting_extent);
61 static int sunlabel_write(FILE * outfile);
62 static int genboot_size(int starting_extent);
63 static int genboot_write(FILE * outfile);
66 * Set the virtual geometry in the disk label.
67 * If we like to make the geometry variable, we may change
68 * dkl_ncyl and dkl_pcyl later.
73 i_to_4_byte(cd_label.dkl_vtoc.v_version, V_VERSION);
74 i_to_2_byte(cd_label.dkl_vtoc.v_nparts, NDKMAP);
75 i_to_4_byte(cd_label.dkl_vtoc.v_sanity, VTOC_SANE);
77 i_to_2_byte(cd_label.dkl_rpm, CD_RPM);
78 i_to_2_byte(cd_label.dkl_pcyl, CD_PCYL);
79 i_to_2_byte(cd_label.dkl_apc, CD_APC);
80 i_to_2_byte(cd_label.dkl_intrlv, CD_INTRLV);
81 i_to_2_byte(cd_label.dkl_ncyl, CD_NCYL);
82 i_to_2_byte(cd_label.dkl_acyl, CD_ACYL);
83 i_to_2_byte(cd_label.dkl_nhead, CD_NHEAD);
84 i_to_2_byte(cd_label.dkl_nsect, CD_NSECT);
86 cd_label.dkl_magic[0] = DKL_MAGIC_0;
87 cd_label.dkl_magic[1] = DKL_MAGIC_1;
93 li_to_4_byte(sx86_label.dkl_vtoc.v_sanity, VTOC_SANE);
94 li_to_4_byte(sx86_label.dkl_vtoc.v_version, V_VERSION);
95 li_to_2_byte(sx86_label.dkl_vtoc.v_sectorsz, 512);
96 li_to_2_byte(sx86_label.dkl_vtoc.v_nparts, NX86MAP);
98 li_to_4_byte(sx86_label.dkl_pcyl, CD_PCYL);
99 li_to_4_byte(sx86_label.dkl_ncyl, CD_NCYL);
100 li_to_2_byte(sx86_label.dkl_acyl, CD_ACYL);
101 li_to_2_byte(sx86_label.dkl_bcyl, 0);
103 li_to_4_byte(sx86_label.dkl_nhead, CD_NHEAD);
104 li_to_4_byte(sx86_label.dkl_nsect, CD_NSECT);
105 li_to_2_byte(sx86_label.dkl_intrlv, CD_INTRLV);
106 li_to_2_byte(sx86_label.dkl_skew, 0);
107 li_to_2_byte(sx86_label.dkl_apc, CD_APC);
108 li_to_2_byte(sx86_label.dkl_rpm, CD_RPM);
110 li_to_2_byte(sx86_label.dkl_write_reinstruct, 0);
111 li_to_2_byte(sx86_label.dkl_read_reinstruct, 0);
113 li_to_2_byte(sx86_label.dkl_magic, DKL_MAGIC);
117 * For command line parser: set ASCII label.
120 sparc_boot_label(char *label)
122 strncpy(cd_label.dkl_ascilabel, label, 127);
123 cd_label.dkl_ascilabel[127] = '\0';
127 sunx86_boot_label(char *label)
129 strncpy(sx86_label.dkl_vtoc.v_asciilabel, label, 127);
130 sx86_label.dkl_vtoc.v_asciilabel[127] = '\0';
134 * Parse the command line argument for boot images.
137 scan_sparc_boot(char *files)
148 comerrno(EX_BAD, "Too many boot partitions.\n");
149 boot_files[i++] = files;
150 if ((p = strchr(files, ',')) != NULL)
155 i_to_2_byte(cd_label.dkl_vtoc.v_part[0].p_tag, V_USR);
156 i_to_2_byte(cd_label.dkl_vtoc.v_part[0].p_flag, V_RONLY);
157 for (i = 0; i < NDKMAP; i++) {
159 if (p == NULL || *p == '\0')
161 if (strcmp(p, "...") == '\0')
164 status = stat_filter(p, &statbuf);
165 if (status < 0 || access(p, R_OK) < 0)
166 comerr("Cannot access '%s'.\n", p);
168 i_to_4_byte(cd_label.dkl_map[i].dkl_nblk,
169 roundup(statbuf.st_size, CD_CYLSIZE)/512);
171 i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_tag, V_ROOT);
172 i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_flag, V_RONLY);
177 scan_sunx86_boot(char *files)
188 comerrno(EX_BAD, "Too many boot partitions.\n");
189 boot_files[i++] = files;
190 if ((p = strchr(files, ',')) != NULL)
195 li_to_2_byte(sx86_label.dkl_vtoc.v_part[0].p_tag, V_ROOT); /* UFS */
196 li_to_2_byte(sx86_label.dkl_vtoc.v_part[0].p_flag, V_RONLY);
197 li_to_2_byte(sx86_label.dkl_vtoc.v_part[1].p_tag, V_USR); /* ISO */
198 li_to_2_byte(sx86_label.dkl_vtoc.v_part[1].p_flag, V_RONLY);
199 li_to_2_byte(sx86_label.dkl_vtoc.v_part[2].p_tag, 0); /* ALL */
200 li_to_2_byte(sx86_label.dkl_vtoc.v_part[2].p_flag, 0);
201 for (i = 0; i < NDKMAP; i++) {
203 if (p == NULL || *p == '\0')
205 if (i == 1 || i == 2) {
207 "Partition %d may not have a filename.\n", i);
210 status = stat_filter(p, &statbuf);
211 if (status < 0 || access(p, R_OK) < 0)
212 comerr("Cannot access '%s'.\n", p);
214 li_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_size,
215 roundup(statbuf.st_size, CD_CYLSIZE)/512);
218 li_to_2_byte(sx86_label.dkl_vtoc.v_part[i].p_tag, V_USR);
219 li_to_2_byte(sx86_label.dkl_vtoc.v_part[i].p_flag, V_RONLY);
225 * Finish the Sun disk label and compute the size of the additional data.
238 * Compute the size of the padding for the iso9660 image
239 * to allow the next partition to start on a cylinder boundary.
241 last = roundup(last_extent, (CD_CYLSIZE/SECTOR_SIZE));
243 i_to_4_byte(cd_label.dkl_map[0].dkl_nblk, last*4);
245 for (i = 0; i < NDKMAP; i++) {
247 if (p != NULL && strcmp(p, "...") == '\0') {
251 if ((nblk = a_to_4_byte(cd_label.dkl_map[i].dkl_nblk)) == 0)
254 i_to_4_byte(cd_label.dkl_map[i].dkl_cylno, cyl);
255 cyl += nblk / (CD_CYLSIZE/512);
260 return (last-last_extent+bsize);
264 * A typical Solaris boot/install CD from a Sun CD set looks
267 * UFS Part 0 tag 2 flag 10 start 3839 size 1314560
268 * ISO Part 1 tag 4 flag 10 start 0 size 3839
269 * ALL Part 2 tag 0 flag 0 start 0 size 1318400
279 int partoff = 1; /* The offset of the Solaris 0x82 partition */
283 * Compute the size of the padding for the iso9660 image
284 * to allow the next partition to start on a cylinder boundary.
286 last = roundup(last_extent, (CD_CYLSIZE/SECTOR_SIZE));
288 li_to_4_byte(sx86_label.dkl_vtoc.v_part[1].p_size, last*4);
291 * Note that the Solaris fdisk partition with fdisk signature 0x82
292 * is created at fixed offset 1 sector == 512 Bytes by this
294 * We need subtract this partition offset from all absolute
295 * partition offsets in order to get offsets relative to the
296 * Solaris primary partition.
299 for (i = 0; i < NDKMAP; i++) {
300 if (i == 2) /* Never include the whole disk in */
301 continue; /* size/offset computations */
304 if ((nblk = la_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_size)) == 0)
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);
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);
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;
327 return (last-last_extent+bsize);
331 * Duplicate a partition of the Sun disk label until all partitions are filled up.
334 dup_sun_label(int part)
341 if (part < 1 || part >= NDKMAP)
343 cyl = a_to_4_byte(cd_label.dkl_map[part-1].dkl_cylno);
344 nblk = a_to_4_byte(cd_label.dkl_map[part-1].dkl_nblk);
346 for (i = part; i < NDKMAP; i++) {
347 i_to_4_byte(cd_label.dkl_map[i].dkl_cylno, cyl);
348 i_to_4_byte(cd_label.dkl_map[i].dkl_nblk, nblk);
350 i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_tag, V_ROOT);
351 i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_flag, V_RONLY);
356 * Write out Sun boot partitions.
359 sunboot_write(FILE *outfile)
361 char buffer[SECTOR_SIZE];
369 memset(buffer, 0, sizeof (buffer));
372 * Write padding to the iso9660 image to allow the
373 * boot partitions to start on a cylinder boundary.
375 amt = roundup(last_extent_written, (CD_CYLSIZE/SECTOR_SIZE)) - last_extent_written;
376 for (n = 0; n < amt; n++) {
377 jtwrite(buffer, SECTOR_SIZE, 1, 0, FALSE);
378 xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
379 last_extent_written++;
385 for (; i < NDKMAP; i++) {
386 if (use_sunx86boot && (i == 1 || i == 2))
389 if (p == NULL || *p == '\0')
391 if (p != NULL && strcmp(p, "...") == '\0')
393 if (use_sunx86boot) {
394 if ((nblk = la_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_size)) == 0)
397 if ((nblk = a_to_4_byte(cd_label.dkl_map[i].dkl_nblk)) == 0)
400 if ((f = open(boot_files[i], O_RDONLY| O_BINARY)) < 0)
401 comerr("Cannot open '%s'.\n", boot_files[i]);
404 for (n = 0; n < amt; n++) {
405 memset(buffer, 0, sizeof (buffer));
406 if (read(f, buffer, SECTOR_SIZE) < 0)
407 comerr("Read error on '%s'.\n", boot_files[i]);
408 jtwrite(buffer, SECTOR_SIZE, 1, 0, FALSE);
409 xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
410 last_extent_written++;
414 fprintf(stderr, "Total extents including %s boot = %u\n",
415 use_sunx86boot ? "Solaris x86":"sparc",
416 last_extent_written - session_start);
421 * Do size management for the Sun disk label that is located in the first
425 sunlabel_size(int starting_extent)
427 if (last_extent != session_start)
428 comerrno(EX_BAD, "Cannot create sparc boot on offset != 0.\n");
434 * Cumpute the checksum and write a Sun disk label to the first sector
436 * If the -generic-boot option has been specified too, overlay the
437 * Sun disk label on the firs 512 bytes of the generic boot code.
440 sunlabel_write(FILE *outfile)
442 char buffer[SECTOR_SIZE];
444 register short count = (512/2) - 1;
447 memset(buffer, 0, sizeof (buffer));
449 if ((f = open(genboot_image, O_RDONLY| O_BINARY)) < 0)
450 comerr("Cannot open '%s'.\n", genboot_image);
452 if (read(f, buffer, SECTOR_SIZE) < 0)
453 comerr("Read error on '%s'.\n", genboot_image);
457 if (use_sunx86boot) {
458 if (sx86_label.dkl_vtoc.v_asciilabel[0] == '\0')
459 strcpy(sx86_label.dkl_vtoc.v_asciilabel, CD_X86LABEL);
461 p = (char *)&sx86_label;
462 sx86_label.dkl_cksum[0] = 0;
463 sx86_label.dkl_cksum[1] = 0;
464 while (count-- > 0) {
465 sx86_label.dkl_cksum[0] ^= *p++;
466 sx86_label.dkl_cksum[1] ^= *p++;
468 memcpy(&buffer[0x1BE], &fdisk_part.part, 512-0x1BE);
469 memcpy(&buffer[1024], &sx86_label, 512);
472 * If we don't already have a Sun disk label text
473 * set up the default.
475 if (cd_label.dkl_ascilabel[0] == '\0')
476 strcpy(cd_label.dkl_ascilabel, CD_DEFLABEL);
478 p = (char *)&cd_label;
479 cd_label.dkl_cksum[0] = 0;
480 cd_label.dkl_cksum[1] = 0;
482 cd_label.dkl_cksum[0] ^= *p++;
483 cd_label.dkl_cksum[1] ^= *p++;
485 memcpy(buffer, &cd_label, 512);
488 jtwrite(buffer, SECTOR_SIZE, 1, 0, FALSE);
489 xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
490 last_extent_written++;
495 * Do size management for the generic boot code on sectors 0..16.
498 genboot_size(int starting_extent)
500 if (last_extent > (session_start + 1))
501 comerrno(EX_BAD, "Cannot create generic boot on offset != 0.\n");
502 last_extent = session_start + 16;
507 * Write the generic boot code to sectors 0..16.
508 * If there is a Sun disk label, start writing at sector 1.
511 genboot_write(FILE *outfile)
513 char buffer[SECTOR_SIZE];
517 if ((f = open(genboot_image, O_RDONLY| O_BINARY)) < 0)
518 comerr("Cannot open '%s'.\n", genboot_image);
520 for (i = 0; i < 16; i++) {
521 memset(buffer, 0, sizeof (buffer));
522 if (read(f, buffer, SECTOR_SIZE) < 0)
523 comerr("Read error on '%s'.\n", genboot_image);
525 if (i != 0 || last_extent_written == session_start) {
526 jtwrite(buffer, SECTOR_SIZE, 1, 0, FALSE);
527 xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
528 last_extent_written++;
535 struct output_fragment sunboot_desc = {NULL, NULL, NULL, sunboot_write, "Sun Boot" };
536 struct output_fragment sunlabel_desc = {NULL, sunlabel_size, NULL, sunlabel_write, "Sun Disk Label" };
537 struct output_fragment genboot_desc = {NULL, genboot_size, NULL, genboot_write, "Generic Boot" };