11590Srgrimes/*- 21590Srgrimes * Copyright (c) 2018 iXsystems, Inc. 31590Srgrimes * All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241590Srgrimes * SUCH DAMAGE. 251590Srgrimes */ 261590Srgrimes 271590Srgrimes#include <sys/cdefs.h> 281590Srgrimes#include <err.h> 291590Srgrimes#include <getopt.h> 3087675Smarkm#include <libgen.h> 3187675Smarkm#include <stdbool.h> 3287675Smarkm#include <stdio.h> 3387675Smarkm 341590Srgrimes#include "cd9660.h" 3528695Scharnier#include "cd9660_eltorito.h" 361590Srgrimes 371590Srgrimes#include "etdump.h" 3887675Smarkm 391590Srgrimesconst char * 401590Srgrimessystem_id_string(u_char system_id) 4187675Smarkm{ 4228695Scharnier 431590Srgrimes switch (system_id) { 441590Srgrimes case ET_SYS_X86: 451590Srgrimes return ("i386"); 461590Srgrimes case ET_SYS_PPC: 471590Srgrimes return ("powerpc"); 481590Srgrimes case ET_SYS_MAC: 491590Srgrimes return ("mac"); 501590Srgrimes case ET_SYS_EFI: 511590Srgrimes return ("efi"); 521590Srgrimes default: 5328695Scharnier return ("invalid"); 5428695Scharnier } 5573255Simp} 5625777Sache 571590Srgrimesconst char * 581590Srgrimesmedia_type_string(u_char media_type) 591590Srgrimes{ 601590Srgrimes 611590Srgrimes switch (media_type) { 6229434Sache case ET_MEDIA_NOEM: 631590Srgrimes return ("no emulation"); 64202200Sed case ET_MEDIA_12FDD: 65233269Sglebius return ("1.2MB FDD"); 66233269Sglebius case ET_MEDIA_144FDD: 671590Srgrimes return ("1.44MB FDD"); 6883242Sdd case ET_MEDIA_288FDD: 6983242Sdd return ("2.88MB FDD"); 7073255Simp case ET_MEDIA_HDD: 7173255Simp return ("HDD"); 721590Srgrimes default: 73227200Sed return ("invalid"); 7473255Simp } 7573255Simp} 7673255Simp 7773255Simpstatic int 78227200Sedread_sector(FILE *iso, daddr_t sector, char *buffer) 79227200Sed{ 80227200Sed 811590Srgrimes if (fseek(iso, sector * ISO_DEFAULT_BLOCK_SIZE, SEEK_SET) != 0) { 82155875Scognet return (errno); 83200156Sed } 84155875Scognet if (fread(buffer, ISO_DEFAULT_BLOCK_SIZE, 1, iso) != 1) { 85155875Scognet return (errno); 86155875Scognet } 87155875Scognet return (0); 88200156Sed} 89155875Scognet 90155875Scognetstatic bool 91155875Scognetboot_catalog_valid(char *entry) 92155875Scognet{ 93155875Scognet boot_catalog_validation_entry *ve; 94155875Scognet int16_t checksum, sum; 951590Srgrimes unsigned char *csptr; 9673255Simp size_t i; 971590Srgrimes 981590Srgrimes ve = (boot_catalog_validation_entry *)entry; 99200156Sed 10073255Simp checksum = isonum_721(ve->checksum); 10183082Sru cd9660_721(0, ve->checksum); 10273255Simp csptr = (unsigned char *)ve; 10373255Simp 10483242Sdd for (i = sum = 0; i < sizeof(*ve); i += 2) { 10583242Sdd sum += (int16_t)csptr[i]; 10673255Simp sum += 256 * (int16_t)csptr[i + 1]; 1071590Srgrimes } 10825777Sache if (sum + checksum != 0) { 10925777Sache return (false); 11073255Simp } 1111590Srgrimes 1121590Srgrimes cd9660_721(checksum, ve->checksum); 1131590Srgrimes return (true); 1141590Srgrimes} 1151590Srgrimes 1161590Srgrimesstatic int 11773255Simpdump_section(char *buffer, size_t bufsize, size_t offset, FILE *outfile, 11873255Simp const char *filename, struct outputter *outputter) 11973255Simp{ 12073255Simp boot_catalog_section_header *sh; 12173255Simp u_char platform_id; 12273255Simp int i; 12373255Simp size_t entry_offset; 1241590Srgrimes boot_catalog_section_entry *entry; 1251590Srgrimes 12628695Scharnier if (offset + sizeof(boot_catalog_section_header) > bufsize) 1271590Srgrimes errx(1, "%s: section header out of bounds", filename); 1281590Srgrimes sh = (boot_catalog_section_header *)&buffer[offset]; 1291590Srgrimes if (outputter->output_section != NULL) { 1301590Srgrimes outputter->output_section(outfile, filename, sh); 13128695Scharnier } 1321590Srgrimes 13373255Simp platform_id = sh->platform_id[0]; 13473255Simp 13573320Simp if (outputter->output_entry != NULL) { 13673255Simp for (i = 1; i <= (int)sh->num_section_entries[0]; i++) { 13773320Simp entry_offset = offset + i * ET_BOOT_ENTRY_SIZE; 13873320Simp if (entry_offset + sizeof(boot_catalog_section_entry) > 13973255Simp bufsize) 14073255Simp errx(1, "%s: section entry out of bounds", 1411590Srgrimes filename); 1421590Srgrimes entry = 1431590Srgrimes (boot_catalog_section_entry *)&buffer[entry_offset]; 1441590Srgrimes outputter->output_entry(outfile, filename, entry, 1451590Srgrimes platform_id, false); 146200156Sed } 147200156Sed } 1481590Srgrimes 149200156Sed return (1 + (int)sh->num_section_entries[0]); 150155875Scognet} 15173255Simp 15283082Srustatic void 153200156Seddump_eltorito(FILE *iso, const char *filename, FILE *outfile, 15473255Simp struct outputter *outputter) 15573255Simp{ 15673255Simp char buffer[ISO_DEFAULT_BLOCK_SIZE], *entry; 15787675Smarkm boot_volume_descriptor *bvd; 15873255Simp daddr_t boot_catalog; 15973255Simp size_t offset; 16073255Simp int entry_count; 16183082Sru 16283082Sru if (read_sector(iso, 17, buffer) != 0) 163200156Sed err(1, "failed to read from image"); 16483082Sru 16583082Sru bvd = (boot_volume_descriptor *)buffer; 16683082Sru if (memcmp(bvd->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5) != 0) 16783082Sru warnx("%s: not a valid ISO", filename); 16883082Sru if (bvd->boot_record_indicator[0] != ISO_VOLUME_DESCRIPTOR_BOOT || 16973255Simp memcmp(bvd->boot_system_identifier, ET_ID, 23) != 0) 17073255Simp warnx("%s: not an El Torito bootable ISO", filename); 17173255Simp 17273255Simp boot_catalog = isonum_731(bvd->boot_catalog_pointer); 173200156Sed 17428695Scharnier if (read_sector(iso, boot_catalog, buffer) != 0) 1751590Srgrimes err(1, "failed to read from image"); 1761590Srgrimes 1771590Srgrimes entry = buffer; 1781590Srgrimes offset = 0; 17928695Scharnier 180201224Sed if (!boot_catalog_valid(entry)) 18128695Scharnier warnx("%s: boot catalog checksum is invalid", filename); 18273320Simp 18328695Scharnier if (outputter->output_image != NULL) 18428695Scharnier outputter->output_image(outfile, filename, bvd); 18528695Scharnier 1861590Srgrimes offset += ET_BOOT_ENTRY_SIZE; 18773255Simp entry = &buffer[offset]; 1881590Srgrimes if (outputter->output_entry != NULL) 18973255Simp outputter->output_entry(outfile, filename, 190233269Sglebius (boot_catalog_section_entry *)entry, 0, true); 1911590Srgrimes 1921590Srgrimes offset += ET_BOOT_ENTRY_SIZE; 1931590Srgrimes 19429434Sache while (offset < ISO_DEFAULT_BLOCK_SIZE) { 1951590Srgrimes entry = &buffer[offset]; 1961590Srgrimes 197233269Sglebius if ((uint8_t)entry[0] != ET_SECTION_HEADER_MORE && 198233269Sglebius (uint8_t)entry[0] != ET_SECTION_HEADER_LAST) 19987675Smarkm break; 20069231Skris 20176367Skris entry_count = dump_section(buffer, sizeof(buffer), offset, 2021590Srgrimes outfile, filename, outputter); 20369231Skris 20469231Skris offset += entry_count * ET_BOOT_ENTRY_SIZE; 20569231Skris } 2061590Srgrimes} 2071590Srgrimes 2081590Srgrimesstatic void 20969231Skrisusage(const char *progname) 21069231Skris{ 21166557Sn_hibma char *path; 21266557Sn_hibma 2131590Srgrimes path = strdup(progname); 2141590Srgrimes 2151590Srgrimes fprintf(stderr, "usage: %s [-f format] [-o filename] filename [...]\n", 2161590Srgrimes basename(path)); 2171590Srgrimes fprintf(stderr, "\tsupported output formats: shell, text\n"); 2181590Srgrimes exit(1); 2191590Srgrimes} 2201590Srgrimes 2211590Srgrimesint 2221590Srgrimesmain(int argc, char **argv) 2231590Srgrimes{ 2241590Srgrimes int ch, i; 2251590Srgrimes FILE *outfile, *iso; 226233269Sglebius struct outputter *outputter; 227233269Sglebius 228233269Sglebius outfile = stdout; 2291590Srgrimes outputter = output_text; 230233269Sglebius 231233269Sglebius static struct option longopts[] = { 232233269Sglebius { "format", required_argument, NULL, 'f' }, 23363909Sasmodai { "output", required_argument, NULL, 'o' }, 234233269Sglebius { NULL, 0, NULL, 0 }, 2351590Srgrimes }; 236233269Sglebius 2371590Srgrimes while ((ch = getopt_long(argc, argv, "f:o:", longopts, NULL)) != -1) { 23876367Skris switch (ch) { 23976367Skris case 'f': 24076367Skris if (strcmp(optarg, "shell") == 0) 241233269Sglebius outputter = output_shell; 24276367Skris else if (strcmp(optarg, "text") == 0) 243241848Seadler outputter = output_text; 244241848Seadler else 24576367Skris usage(argv[0]); 246223940Sobrien break; 247233269Sglebius case 'o': 248233269Sglebius if (strcmp(optarg, "-") == 0) { 249233269Sglebius outfile = stdout; 250233269Sglebius } else if ((outfile = fopen(optarg, "w")) == NULL) { 25150776Sdbaker err(1, "unable to open %s for output", optarg); 252175346Sdas } 253233269Sglebius break; 2541590Srgrimes default: 255233269Sglebius usage(argv[0]); 256233269Sglebius } 257233269Sglebius } 258175346Sdas 259175346Sdas argc -= optind; 260175346Sdas argv += optind; 261233269Sglebius 262233269Sglebius for (i = 0; i < argc; i++) { 2631590Srgrimes if (strcmp(argv[i], "-") == 0) { 264175346Sdas iso = stdin; 265233269Sglebius } else { 266233269Sglebius iso = fopen(argv[i], "r"); 267233269Sglebius if (iso == NULL) 268233269Sglebius err(1, "could not open %s", argv[i]); 269233269Sglebius } 270233269Sglebius dump_eltorito(iso, argv[i], outfile, outputter); 27129434Sache } 272233269Sglebius} 273233269Sglebius