Logo Search packages:      
Sourcecode: cdrkit version File versions  Download package

boot.c

/*
 * 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" };

Generated by  Doxygen 1.6.0   Back to index