diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
commit | 71dc8760ff4de5f365330d1bc571d934deb54af9 (patch) | |
tree | 7346d42a282562a3937d82307012b5857d642ce6 /genisoimage/boot.c | |
download | cdrkit-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.c | 537 |
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" }; |