543 lines
14 KiB
C
543 lines
14 KiB
C
/* @(#)boot.c 1.28 16/10/23 Copyright 1999-2016 J. Schilling */
|
|
#include <schily/mconfig.h>
|
|
#ifndef lint
|
|
static UConst char sccsid[] =
|
|
"@(#)boot.c 1.28 16/10/23 Copyright 1999-2016 J. Schilling";
|
|
#endif
|
|
/*
|
|
* Support for generic boot (sector 0..16)
|
|
* and to boot Sun sparc and Sun x86 systems.
|
|
*
|
|
* Copyright (c) 1999-2016 J. Schilling
|
|
*/
|
|
/*@@C@@*/
|
|
|
|
#include "mkisofs.h"
|
|
#include <schily/fcntl.h>
|
|
#include <schily/utypes.h>
|
|
#include <schily/intcvt.h>
|
|
#include <schily/schily.h>
|
|
#include "sunlabel.h"
|
|
|
|
extern int use_sunx86boot;
|
|
|
|
LOCAL struct sun_label cd_label;
|
|
LOCAL struct x86_label sx86_label;
|
|
LOCAL struct pc_part fdisk_part;
|
|
LOCAL char *boot_files[NDKMAP]; /* Change this for > 8 x86 parts */
|
|
|
|
LOCAL void init_sparc_label __PR((void));
|
|
LOCAL void init_sunx86_label __PR((void));
|
|
EXPORT int sparc_boot_label __PR((char *label));
|
|
EXPORT int sunx86_boot_label __PR((char *label));
|
|
EXPORT int scan_sparc_boot __PR((char *files));
|
|
EXPORT int scan_sunx86_boot __PR((char *files));
|
|
EXPORT int make_sun_label __PR((void));
|
|
EXPORT int make_sunx86_label __PR((void));
|
|
LOCAL void dup_sun_label __PR((int part));
|
|
LOCAL int sunboot_write __PR((FILE *outfile));
|
|
LOCAL int sunlabel_size __PR((UInt32_t starting_extent));
|
|
LOCAL int sunlabel_write __PR((FILE *outfile));
|
|
LOCAL int genboot_size __PR((UInt32_t starting_extent));
|
|
LOCAL int genboot_write __PR((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.
|
|
*/
|
|
LOCAL 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;
|
|
}
|
|
|
|
LOCAL 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.
|
|
*/
|
|
EXPORT int
|
|
sparc_boot_label(label)
|
|
char *label;
|
|
{
|
|
strncpy(cd_label.dkl_ascilabel, label, 127);
|
|
cd_label.dkl_ascilabel[127] = '\0';
|
|
return (1);
|
|
}
|
|
|
|
EXPORT int
|
|
sunx86_boot_label(label)
|
|
char *label;
|
|
{
|
|
strncpy(sx86_label.dkl_vtoc.v_asciilabel, label, 127);
|
|
sx86_label.dkl_vtoc.v_asciilabel[127] = '\0';
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Parse the command line argument for boot images.
|
|
*/
|
|
EXPORT int
|
|
scan_sparc_boot(files)
|
|
char *files;
|
|
{
|
|
char *p;
|
|
int i = 1;
|
|
struct stat statbuf;
|
|
int status;
|
|
extern int use_sparcboot;
|
|
extern int use_sunx86boot;
|
|
|
|
if (use_sunx86boot)
|
|
comerrno(EX_BAD,
|
|
_("-sparc-boot and -sunx86-boot are mutual exclusive.\n"));
|
|
use_sparcboot++;
|
|
|
|
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);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
EXPORT int
|
|
scan_sunx86_boot(files)
|
|
char *files;
|
|
{
|
|
char *p;
|
|
int i = 0;
|
|
struct stat statbuf;
|
|
int status;
|
|
extern int use_sparcboot;
|
|
extern int use_sunx86boot;
|
|
|
|
if (use_sparcboot)
|
|
comerrno(EX_BAD,
|
|
_("-sparc-boot and -sunx86-boot are mutual exclusive.\n"));
|
|
use_sunx86boot++;
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Finish the Sun disk label and compute the size of the additional data.
|
|
*/
|
|
EXPORT 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
|
|
*/
|
|
EXPORT 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 */
|
|
|
|
/*
|
|
* 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 */
|
|
|
|
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.
|
|
*/
|
|
LOCAL void
|
|
dup_sun_label(part)
|
|
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.
|
|
*/
|
|
LOCAL int
|
|
sunboot_write(outfile)
|
|
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++) {
|
|
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]);
|
|
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.
|
|
*/
|
|
LOCAL int
|
|
sunlabel_size(starting_extent)
|
|
UInt32_t starting_extent;
|
|
{
|
|
if (last_extent != session_start)
|
|
comerrno(EX_BAD, _("Cannot create sparc boot on offset != 0.\n"));
|
|
last_extent++;
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Compute 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 first 512 bytes of the generic boot code.
|
|
*/
|
|
LOCAL int
|
|
sunlabel_write(outfile)
|
|
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, sizeof (fdisk_part.part));
|
|
p = &buffer[510];
|
|
*p++ = 0x55;
|
|
*p = 0xAA;
|
|
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);
|
|
}
|
|
|
|
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.
|
|
*/
|
|
LOCAL int
|
|
genboot_size(starting_extent)
|
|
UInt32_t 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.
|
|
*/
|
|
LOCAL int
|
|
genboot_write(outfile)
|
|
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) {
|
|
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" };
|