summaryrefslogtreecommitdiff
path: root/genisoimage/boot.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-12-31 05:04:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2012-12-31 05:04:42 +0400
commit71dc8760ff4de5f365330d1bc571d934deb54af9 (patch)
tree7346d42a282562a3937d82307012b5857d642ce6 /genisoimage/boot.c
downloadcdrkit-upstream/1.1.11.tar.gz
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'genisoimage/boot.c')
-rw-r--r--genisoimage/boot.c537
1 files changed, 537 insertions, 0 deletions
diff --git a/genisoimage/boot.c b/genisoimage/boot.c
new file mode 100644
index 0000000..51b6fb7
--- /dev/null
+++ b/genisoimage/boot.c
@@ -0,0 +1,537 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)boot.c 1.13 04/02/22 Copyright 1999-2003 J. Schilling */
+/*
+ * Support for generic boot (sector 0..16)
+ * and to boot Sun sparc and Sun x86 systems.
+ *
+ * Copyright (c) 1999-2003 J. Schilling
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <mconfig.h>
+#include "genisoimage.h"
+#include <fctldefs.h>
+#include <utypes.h>
+#include <intcvt.h>
+#include <schily.h>
+#include "sunlabel.h"
+
+extern int use_sunx86boot;
+
+static struct sun_label cd_label;
+static struct x86_label sx86_label;
+static struct pc_part fdisk_part;
+static char *boot_files[NDKMAP]; /* Change this for > 8 x86 parts */
+
+static void init_sparc_label(void);
+static void init_sunx86_label(void);
+void sparc_boot_label(char *label);
+void sunx86_boot_label(char *label);
+void scan_sparc_boot(char *files);
+void scan_sunx86_boot(char *files);
+int make_sun_label(void);
+int make_sunx86_label(void);
+static void dup_sun_label(int part);
+static int sunboot_write(FILE *outfile);
+static int sunlabel_size(int starting_extent);
+static int sunlabel_write(FILE * outfile);
+static int genboot_size(int starting_extent);
+static int genboot_write(FILE * outfile);
+
+/*
+ * Set the virtual geometry in the disk label.
+ * If we like to make the geometry variable, we may change
+ * dkl_ncyl and dkl_pcyl later.
+ */
+static void
+init_sparc_label()
+{
+ i_to_4_byte(cd_label.dkl_vtoc.v_version, V_VERSION);
+ i_to_2_byte(cd_label.dkl_vtoc.v_nparts, NDKMAP);
+ i_to_4_byte(cd_label.dkl_vtoc.v_sanity, VTOC_SANE);
+
+ i_to_2_byte(cd_label.dkl_rpm, CD_RPM);
+ i_to_2_byte(cd_label.dkl_pcyl, CD_PCYL);
+ i_to_2_byte(cd_label.dkl_apc, CD_APC);
+ i_to_2_byte(cd_label.dkl_intrlv, CD_INTRLV);
+ i_to_2_byte(cd_label.dkl_ncyl, CD_NCYL);
+ i_to_2_byte(cd_label.dkl_acyl, CD_ACYL);
+ i_to_2_byte(cd_label.dkl_nhead, CD_NHEAD);
+ i_to_2_byte(cd_label.dkl_nsect, CD_NSECT);
+
+ cd_label.dkl_magic[0] = DKL_MAGIC_0;
+ cd_label.dkl_magic[1] = DKL_MAGIC_1;
+}
+
+static void
+init_sunx86_label()
+{
+ li_to_4_byte(sx86_label.dkl_vtoc.v_sanity, VTOC_SANE);
+ li_to_4_byte(sx86_label.dkl_vtoc.v_version, V_VERSION);
+ li_to_2_byte(sx86_label.dkl_vtoc.v_sectorsz, 512);
+ li_to_2_byte(sx86_label.dkl_vtoc.v_nparts, NX86MAP);
+
+ li_to_4_byte(sx86_label.dkl_pcyl, CD_PCYL);
+ li_to_4_byte(sx86_label.dkl_ncyl, CD_NCYL);
+ li_to_2_byte(sx86_label.dkl_acyl, CD_ACYL);
+ li_to_2_byte(sx86_label.dkl_bcyl, 0);
+
+ li_to_4_byte(sx86_label.dkl_nhead, CD_NHEAD);
+ li_to_4_byte(sx86_label.dkl_nsect, CD_NSECT);
+ li_to_2_byte(sx86_label.dkl_intrlv, CD_INTRLV);
+ li_to_2_byte(sx86_label.dkl_skew, 0);
+ li_to_2_byte(sx86_label.dkl_apc, CD_APC);
+ li_to_2_byte(sx86_label.dkl_rpm, CD_RPM);
+
+ li_to_2_byte(sx86_label.dkl_write_reinstruct, 0);
+ li_to_2_byte(sx86_label.dkl_read_reinstruct, 0);
+
+ li_to_2_byte(sx86_label.dkl_magic, DKL_MAGIC);
+}
+
+/*
+ * For command line parser: set ASCII label.
+ */
+void
+sparc_boot_label(char *label)
+{
+ strncpy(cd_label.dkl_ascilabel, label, 127);
+ cd_label.dkl_ascilabel[127] = '\0';
+}
+
+void
+sunx86_boot_label(char *label)
+{
+ strncpy(sx86_label.dkl_vtoc.v_asciilabel, label, 127);
+ sx86_label.dkl_vtoc.v_asciilabel[127] = '\0';
+}
+
+/*
+ * Parse the command line argument for boot images.
+ */
+void
+scan_sparc_boot(char *files)
+{
+ char *p;
+ int i = 1;
+ struct stat statbuf;
+ int status;
+
+ init_sparc_label();
+
+ do {
+ if (i >= NDKMAP)
+ comerrno(EX_BAD, "Too many boot partitions.\n");
+ boot_files[i++] = files;
+ if ((p = strchr(files, ',')) != NULL)
+ *p++ = '\0';
+ files = p;
+ } while (p);
+
+ i_to_2_byte(cd_label.dkl_vtoc.v_part[0].p_tag, V_USR);
+ i_to_2_byte(cd_label.dkl_vtoc.v_part[0].p_flag, V_RONLY);
+ for (i = 0; i < NDKMAP; i++) {
+ p = boot_files[i];
+ if (p == NULL || *p == '\0')
+ continue;
+ if (strcmp(p, "...") == '\0')
+ break;
+
+ status = stat_filter(p, &statbuf);
+ if (status < 0 || access(p, R_OK) < 0)
+ comerr("Cannot access '%s'.\n", p);
+
+ i_to_4_byte(cd_label.dkl_map[i].dkl_nblk,
+ roundup(statbuf.st_size, CD_CYLSIZE)/512);
+
+ i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_tag, V_ROOT);
+ i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_flag, V_RONLY);
+ }
+}
+
+void
+scan_sunx86_boot(char *files)
+{
+ char *p;
+ int i = 0;
+ struct stat statbuf;
+ int status;
+
+ init_sunx86_label();
+
+ do {
+ if (i >= NDKMAP)
+ comerrno(EX_BAD, "Too many boot partitions.\n");
+ boot_files[i++] = files;
+ if ((p = strchr(files, ',')) != NULL)
+ *p++ = '\0';
+ files = p;
+ } while (p);
+
+ li_to_2_byte(sx86_label.dkl_vtoc.v_part[0].p_tag, V_ROOT); /* UFS */
+ li_to_2_byte(sx86_label.dkl_vtoc.v_part[0].p_flag, V_RONLY);
+ li_to_2_byte(sx86_label.dkl_vtoc.v_part[1].p_tag, V_USR); /* ISO */
+ li_to_2_byte(sx86_label.dkl_vtoc.v_part[1].p_flag, V_RONLY);
+ li_to_2_byte(sx86_label.dkl_vtoc.v_part[2].p_tag, 0); /* ALL */
+ li_to_2_byte(sx86_label.dkl_vtoc.v_part[2].p_flag, 0);
+ for (i = 0; i < NDKMAP; i++) {
+ p = boot_files[i];
+ if (p == NULL || *p == '\0')
+ continue;
+ if (i == 1 || i == 2) {
+ comerrno(EX_BAD,
+ "Partition %d may not have a filename.\n", i);
+ }
+
+ status = stat_filter(p, &statbuf);
+ if (status < 0 || access(p, R_OK) < 0)
+ comerr("Cannot access '%s'.\n", p);
+
+ li_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_size,
+ roundup(statbuf.st_size, CD_CYLSIZE)/512);
+
+ if (i > 2) {
+ li_to_2_byte(sx86_label.dkl_vtoc.v_part[i].p_tag, V_USR);
+ li_to_2_byte(sx86_label.dkl_vtoc.v_part[i].p_flag, V_RONLY);
+ }
+ }
+}
+
+/*
+ * Finish the Sun disk label and compute the size of the additional data.
+ */
+int
+make_sun_label()
+{
+ int last;
+ int cyl = 0;
+ int nblk;
+ int bsize;
+ int i;
+ char *p;
+
+ /*
+ * Compute the size of the padding for the iso9660 image
+ * to allow the next partition to start on a cylinder boundary.
+ */
+ last = roundup(last_extent, (CD_CYLSIZE/SECTOR_SIZE));
+
+ i_to_4_byte(cd_label.dkl_map[0].dkl_nblk, last*4);
+ bsize = 0;
+ for (i = 0; i < NDKMAP; i++) {
+ p = boot_files[i];
+ if (p != NULL && strcmp(p, "...") == '\0') {
+ dup_sun_label(i);
+ break;
+ }
+ if ((nblk = a_to_4_byte(cd_label.dkl_map[i].dkl_nblk)) == 0)
+ continue;
+
+ i_to_4_byte(cd_label.dkl_map[i].dkl_cylno, cyl);
+ cyl += nblk / (CD_CYLSIZE/512);
+ if (i > 0)
+ bsize += nblk;
+ }
+ bsize /= 4;
+ return (last-last_extent+bsize);
+}
+
+/*
+ * A typical Solaris boot/install CD from a Sun CD set looks
+ * this way:
+ *
+ * UFS Part 0 tag 2 flag 10 start 3839 size 1314560
+ * ISO Part 1 tag 4 flag 10 start 0 size 3839
+ * ALL Part 2 tag 0 flag 0 start 0 size 1318400
+ */
+int
+make_sunx86_label()
+{
+ int last;
+ int cyl = 0;
+ int nblk;
+ int bsize;
+ int i;
+ int partoff = 1; /* The offset of the Solaris 0x82 partition */
+ char *p;
+
+ /*
+ * Compute the size of the padding for the iso9660 image
+ * to allow the next partition to start on a cylinder boundary.
+ */
+ last = roundup(last_extent, (CD_CYLSIZE/SECTOR_SIZE));
+
+ li_to_4_byte(sx86_label.dkl_vtoc.v_part[1].p_size, last*4);
+
+ /*
+ * Note that the Solaris fdisk partition with fdisk signature 0x82
+ * is created at fixed offset 1 sector == 512 Bytes by this
+ * implementation.
+ * We need subtract this partition offset from all absolute
+ * partition offsets in order to get offsets relative to the
+ * Solaris primary partition.
+ */
+ bsize = 0;
+ for (i = 0; i < NDKMAP; i++) {
+ if (i == 2) /* Never include the whole disk in */
+ continue; /* size/offset computations */
+ p = boot_files[i];
+
+ if ((nblk = la_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_size)) == 0)
+ continue;
+
+ li_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_start,
+ cyl*(CD_CYLSIZE/512)-partoff);
+ cyl += nblk / (CD_CYLSIZE/512);
+ if (i == 0 || i > 2)
+ bsize += nblk;
+ }
+ li_to_4_byte(sx86_label.dkl_vtoc.v_part[0].p_start, last*4-partoff);
+ li_to_4_byte(sx86_label.dkl_vtoc.v_part[1].p_start, 0);
+ li_to_4_byte(sx86_label.dkl_vtoc.v_part[1].p_size, last*4-partoff);
+ li_to_4_byte(sx86_label.dkl_vtoc.v_part[2].p_start, 0);
+ li_to_4_byte(sx86_label.dkl_vtoc.v_part[2].p_size, last*4+bsize);
+
+ fdisk_part.part[0].pr_status = STATUS_ACTIVE;
+ fdisk_part.part[0].pr_type = TYPE_SOLARIS;
+ li_to_4_byte(fdisk_part.part[0].pr_partoff, partoff);
+ li_to_4_byte(fdisk_part.part[0].pr_nsect, last*4+bsize-partoff);
+ fdisk_part.magic[0] = 0x55;
+ fdisk_part.magic[1] = 0xAA;
+
+ bsize /= 4;
+ return (last-last_extent+bsize);
+}
+
+/*
+ * Duplicate a partition of the Sun disk label until all partitions are filled up.
+ */
+static void
+dup_sun_label(int part)
+{
+ int cyl;
+ int nblk;
+ int i;
+
+
+ if (part < 1 || part >= NDKMAP)
+ part = 1;
+ cyl = a_to_4_byte(cd_label.dkl_map[part-1].dkl_cylno);
+ nblk = a_to_4_byte(cd_label.dkl_map[part-1].dkl_nblk);
+
+ for (i = part; i < NDKMAP; i++) {
+ i_to_4_byte(cd_label.dkl_map[i].dkl_cylno, cyl);
+ i_to_4_byte(cd_label.dkl_map[i].dkl_nblk, nblk);
+
+ i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_tag, V_ROOT);
+ i_to_2_byte(cd_label.dkl_vtoc.v_part[i].p_flag, V_RONLY);
+ }
+}
+
+/*
+ * Write out Sun boot partitions.
+ */
+static int
+sunboot_write(FILE *outfile)
+{
+ char buffer[SECTOR_SIZE];
+ int i;
+ int n;
+ int nblk;
+ int amt;
+ int f;
+ char *p;
+
+ memset(buffer, 0, sizeof (buffer));
+
+ /*
+ * Write padding to the iso9660 image to allow the
+ * boot partitions to start on a cylinder boundary.
+ */
+ amt = roundup(last_extent_written, (CD_CYLSIZE/SECTOR_SIZE)) - last_extent_written;
+ for (n = 0; n < amt; n++) {
+ jtwrite(buffer, SECTOR_SIZE, 1, 0, FALSE);
+ xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
+ last_extent_written++;
+ }
+ if (use_sunx86boot)
+ i = 0;
+ else
+ i = 1;
+ for (; i < NDKMAP; i++) {
+ if (use_sunx86boot && (i == 1 || i == 2))
+ continue;
+ p = boot_files[i];
+ if (p == NULL || *p == '\0')
+ continue;
+ if (p != NULL && strcmp(p, "...") == '\0')
+ break;
+ if (use_sunx86boot) {
+ if ((nblk = la_to_4_byte(sx86_label.dkl_vtoc.v_part[i].p_size)) == 0)
+ continue;
+ } else {
+ if ((nblk = a_to_4_byte(cd_label.dkl_map[i].dkl_nblk)) == 0)
+ continue;
+ }
+ if ((f = open(boot_files[i], O_RDONLY| O_BINARY)) < 0)
+ comerr("Cannot open '%s'.\n", boot_files[i]);
+
+ amt = nblk / 4;
+ for (n = 0; n < amt; n++) {
+ memset(buffer, 0, sizeof (buffer));
+ if (read(f, buffer, SECTOR_SIZE) < 0)
+ comerr("Read error on '%s'.\n", boot_files[i]);
+ jtwrite(buffer, SECTOR_SIZE, 1, 0, FALSE);
+ xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
+ last_extent_written++;
+ }
+ close(f);
+ }
+ fprintf(stderr, "Total extents including %s boot = %u\n",
+ use_sunx86boot ? "Solaris x86":"sparc",
+ last_extent_written - session_start);
+ return (0);
+}
+
+/*
+ * Do size management for the Sun disk label that is located in the first
+ * sector of a disk.
+ */
+static int
+sunlabel_size(int starting_extent)
+{
+ if (last_extent != session_start)
+ comerrno(EX_BAD, "Cannot create sparc boot on offset != 0.\n");
+ last_extent++;
+ return (0);
+}
+
+/*
+ * Cumpute the checksum and write a Sun disk label to the first sector
+ * of the disk.
+ * If the -generic-boot option has been specified too, overlay the
+ * Sun disk label on the firs 512 bytes of the generic boot code.
+ */
+static int
+sunlabel_write(FILE *outfile)
+{
+ char buffer[SECTOR_SIZE];
+ register char *p;
+ register short count = (512/2) - 1;
+ int f;
+
+ memset(buffer, 0, sizeof (buffer));
+ if (genboot_image) {
+ if ((f = open(genboot_image, O_RDONLY| O_BINARY)) < 0)
+ comerr("Cannot open '%s'.\n", genboot_image);
+
+ if (read(f, buffer, SECTOR_SIZE) < 0)
+ comerr("Read error on '%s'.\n", genboot_image);
+ close(f);
+ }
+
+ if (use_sunx86boot) {
+ if (sx86_label.dkl_vtoc.v_asciilabel[0] == '\0')
+ strcpy(sx86_label.dkl_vtoc.v_asciilabel, CD_X86LABEL);
+
+ p = (char *)&sx86_label;
+ sx86_label.dkl_cksum[0] = 0;
+ sx86_label.dkl_cksum[1] = 0;
+ while (count-- > 0) {
+ sx86_label.dkl_cksum[0] ^= *p++;
+ sx86_label.dkl_cksum[1] ^= *p++;
+ }
+ memcpy(&buffer[0x1BE], &fdisk_part.part, 512-0x1BE);
+ memcpy(&buffer[1024], &sx86_label, 512);
+ } else {
+ /*
+ * If we don't already have a Sun disk label text
+ * set up the default.
+ */
+ if (cd_label.dkl_ascilabel[0] == '\0')
+ strcpy(cd_label.dkl_ascilabel, CD_DEFLABEL);
+
+ p = (char *)&cd_label;
+ cd_label.dkl_cksum[0] = 0;
+ cd_label.dkl_cksum[1] = 0;
+ while (count--) {
+ cd_label.dkl_cksum[0] ^= *p++;
+ cd_label.dkl_cksum[1] ^= *p++;
+ }
+ memcpy(buffer, &cd_label, 512);
+ }
+
+ jtwrite(buffer, SECTOR_SIZE, 1, 0, FALSE);
+ xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
+ last_extent_written++;
+ return (0);
+}
+
+/*
+ * Do size management for the generic boot code on sectors 0..16.
+ */
+static int
+genboot_size(int starting_extent)
+{
+ if (last_extent > (session_start + 1))
+ comerrno(EX_BAD, "Cannot create generic boot on offset != 0.\n");
+ last_extent = session_start + 16;
+ return (0);
+}
+
+/*
+ * Write the generic boot code to sectors 0..16.
+ * If there is a Sun disk label, start writing at sector 1.
+ */
+static int
+genboot_write(FILE *outfile)
+{
+ char buffer[SECTOR_SIZE];
+ int i;
+ int f;
+
+ if ((f = open(genboot_image, O_RDONLY| O_BINARY)) < 0)
+ comerr("Cannot open '%s'.\n", genboot_image);
+
+ for (i = 0; i < 16; i++) {
+ memset(buffer, 0, sizeof (buffer));
+ if (read(f, buffer, SECTOR_SIZE) < 0)
+ comerr("Read error on '%s'.\n", genboot_image);
+
+ if (i != 0 || last_extent_written == session_start) {
+ jtwrite(buffer, SECTOR_SIZE, 1, 0, FALSE);
+ xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
+ last_extent_written++;
+ }
+ }
+ close(f);
+ return (0);
+}
+
+struct output_fragment sunboot_desc = {NULL, NULL, NULL, sunboot_write, "Sun Boot" };
+struct output_fragment sunlabel_desc = {NULL, sunlabel_size, NULL, sunlabel_write, "Sun Disk Label" };
+struct output_fragment genboot_desc = {NULL, genboot_size, NULL, genboot_write, "Generic Boot" };