[MKISOFS]
[reactos.git] / reactos / sdk / tools / mkisofs / schilytools / mkisofs / boot.c
diff --git a/reactos/sdk/tools/mkisofs/schilytools/mkisofs/boot.c b/reactos/sdk/tools/mkisofs/schilytools/mkisofs/boot.c
new file mode 100644 (file)
index 0000000..f8ec10b
--- /dev/null
@@ -0,0 +1,542 @@
+/* @(#)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" };