/* * 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 #include "genisoimage.h" #include #include #include #include #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" };