1158d2fcdSBenno Rice /*-
2158d2fcdSBenno Rice * Copyright (c) 2018 iXsystems, Inc.
3158d2fcdSBenno Rice * All rights reserved.
4158d2fcdSBenno Rice *
5158d2fcdSBenno Rice * Redistribution and use in source and binary forms, with or without
6158d2fcdSBenno Rice * modification, are permitted provided that the following conditions
7158d2fcdSBenno Rice * are met:
8158d2fcdSBenno Rice * 1. Redistributions of source code must retain the above copyright
9158d2fcdSBenno Rice * notice, this list of conditions and the following disclaimer.
10158d2fcdSBenno Rice * 2. Redistributions in binary form must reproduce the above copyright
11158d2fcdSBenno Rice * notice, this list of conditions and the following disclaimer in the
12158d2fcdSBenno Rice * documentation and/or other materials provided with the distribution.
13158d2fcdSBenno Rice *
14158d2fcdSBenno Rice * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15158d2fcdSBenno Rice * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16158d2fcdSBenno Rice * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17158d2fcdSBenno Rice * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18158d2fcdSBenno Rice * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19158d2fcdSBenno Rice * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20158d2fcdSBenno Rice * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21158d2fcdSBenno Rice * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22158d2fcdSBenno Rice * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23158d2fcdSBenno Rice * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24158d2fcdSBenno Rice * SUCH DAMAGE.
25158d2fcdSBenno Rice */
26158d2fcdSBenno Rice
27158d2fcdSBenno Rice #include <sys/cdefs.h>
28158d2fcdSBenno Rice #include <err.h>
29158d2fcdSBenno Rice #include <getopt.h>
30158d2fcdSBenno Rice #include <libgen.h>
31158d2fcdSBenno Rice #include <stdbool.h>
32158d2fcdSBenno Rice #include <stdio.h>
33158d2fcdSBenno Rice
34158d2fcdSBenno Rice #include "cd9660.h"
35158d2fcdSBenno Rice #include "cd9660_eltorito.h"
36158d2fcdSBenno Rice
37158d2fcdSBenno Rice #include "etdump.h"
38158d2fcdSBenno Rice
39158d2fcdSBenno Rice const char *
system_id_string(u_char system_id)40158d2fcdSBenno Rice system_id_string(u_char system_id)
41158d2fcdSBenno Rice {
42158d2fcdSBenno Rice
43158d2fcdSBenno Rice switch (system_id) {
44158d2fcdSBenno Rice case ET_SYS_X86:
45158d2fcdSBenno Rice return ("i386");
46158d2fcdSBenno Rice case ET_SYS_PPC:
47158d2fcdSBenno Rice return ("powerpc");
48158d2fcdSBenno Rice case ET_SYS_MAC:
49158d2fcdSBenno Rice return ("mac");
50158d2fcdSBenno Rice case ET_SYS_EFI:
51158d2fcdSBenno Rice return ("efi");
52158d2fcdSBenno Rice default:
53158d2fcdSBenno Rice return ("invalid");
54158d2fcdSBenno Rice }
55158d2fcdSBenno Rice }
56158d2fcdSBenno Rice
57158d2fcdSBenno Rice const char *
media_type_string(u_char media_type)58158d2fcdSBenno Rice media_type_string(u_char media_type)
59158d2fcdSBenno Rice {
60158d2fcdSBenno Rice
61158d2fcdSBenno Rice switch (media_type) {
62158d2fcdSBenno Rice case ET_MEDIA_NOEM:
63158d2fcdSBenno Rice return ("no emulation");
64158d2fcdSBenno Rice case ET_MEDIA_12FDD:
65158d2fcdSBenno Rice return ("1.2MB FDD");
66158d2fcdSBenno Rice case ET_MEDIA_144FDD:
67158d2fcdSBenno Rice return ("1.44MB FDD");
68158d2fcdSBenno Rice case ET_MEDIA_288FDD:
69158d2fcdSBenno Rice return ("2.88MB FDD");
70158d2fcdSBenno Rice case ET_MEDIA_HDD:
71158d2fcdSBenno Rice return ("HDD");
72158d2fcdSBenno Rice default:
73158d2fcdSBenno Rice return ("invalid");
74158d2fcdSBenno Rice }
75158d2fcdSBenno Rice }
76158d2fcdSBenno Rice
77158d2fcdSBenno Rice static int
read_sector(FILE * iso,daddr_t sector,char * buffer)78158d2fcdSBenno Rice read_sector(FILE *iso, daddr_t sector, char *buffer)
79158d2fcdSBenno Rice {
80158d2fcdSBenno Rice
81695fed77SBenno Rice if (fseek(iso, sector * ISO_DEFAULT_BLOCK_SIZE, SEEK_SET) != 0) {
82695fed77SBenno Rice return (errno);
83695fed77SBenno Rice }
84158d2fcdSBenno Rice if (fread(buffer, ISO_DEFAULT_BLOCK_SIZE, 1, iso) != 1) {
85158d2fcdSBenno Rice return (errno);
86158d2fcdSBenno Rice }
87158d2fcdSBenno Rice return (0);
88158d2fcdSBenno Rice }
89158d2fcdSBenno Rice
90158d2fcdSBenno Rice static bool
boot_catalog_valid(char * entry)91158d2fcdSBenno Rice boot_catalog_valid(char *entry)
92158d2fcdSBenno Rice {
93158d2fcdSBenno Rice boot_catalog_validation_entry *ve;
94158d2fcdSBenno Rice int16_t checksum, sum;
95158d2fcdSBenno Rice unsigned char *csptr;
96158d2fcdSBenno Rice size_t i;
97158d2fcdSBenno Rice
98158d2fcdSBenno Rice ve = (boot_catalog_validation_entry *)entry;
99158d2fcdSBenno Rice
100158d2fcdSBenno Rice checksum = isonum_721(ve->checksum);
101158d2fcdSBenno Rice cd9660_721(0, ve->checksum);
102158d2fcdSBenno Rice csptr = (unsigned char *)ve;
103158d2fcdSBenno Rice
104158d2fcdSBenno Rice for (i = sum = 0; i < sizeof(*ve); i += 2) {
105158d2fcdSBenno Rice sum += (int16_t)csptr[i];
106158d2fcdSBenno Rice sum += 256 * (int16_t)csptr[i + 1];
107158d2fcdSBenno Rice }
108158d2fcdSBenno Rice if (sum + checksum != 0) {
109158d2fcdSBenno Rice return (false);
110158d2fcdSBenno Rice }
111158d2fcdSBenno Rice
112158d2fcdSBenno Rice cd9660_721(checksum, ve->checksum);
113158d2fcdSBenno Rice return (true);
114158d2fcdSBenno Rice }
115158d2fcdSBenno Rice
116158d2fcdSBenno Rice static int
dump_section(char * buffer,size_t bufsize,size_t offset,FILE * outfile,const char * filename,struct outputter * outputter)117ddf77ec3SEd Maste dump_section(char *buffer, size_t bufsize, size_t offset, FILE *outfile,
118ddf77ec3SEd Maste const char *filename, struct outputter *outputter)
119158d2fcdSBenno Rice {
120158d2fcdSBenno Rice boot_catalog_section_header *sh;
121158d2fcdSBenno Rice u_char platform_id;
122158d2fcdSBenno Rice int i;
123158d2fcdSBenno Rice size_t entry_offset;
124158d2fcdSBenno Rice boot_catalog_section_entry *entry;
125158d2fcdSBenno Rice
126ddf77ec3SEd Maste if (offset + sizeof(boot_catalog_section_header) > bufsize)
127ddf77ec3SEd Maste errx(1, "%s: section header out of bounds", filename);
128158d2fcdSBenno Rice sh = (boot_catalog_section_header *)&buffer[offset];
129158d2fcdSBenno Rice if (outputter->output_section != NULL) {
130158d2fcdSBenno Rice outputter->output_section(outfile, filename, sh);
131158d2fcdSBenno Rice }
132158d2fcdSBenno Rice
133158d2fcdSBenno Rice platform_id = sh->platform_id[0];
134158d2fcdSBenno Rice
135158d2fcdSBenno Rice if (outputter->output_entry != NULL) {
136158d2fcdSBenno Rice for (i = 1; i <= (int)sh->num_section_entries[0]; i++) {
137158d2fcdSBenno Rice entry_offset = offset + i * ET_BOOT_ENTRY_SIZE;
138ddf77ec3SEd Maste if (entry_offset + sizeof(boot_catalog_section_entry) >
139ddf77ec3SEd Maste bufsize)
140ddf77ec3SEd Maste errx(1, "%s: section entry out of bounds",
141ddf77ec3SEd Maste filename);
142158d2fcdSBenno Rice entry =
143158d2fcdSBenno Rice (boot_catalog_section_entry *)&buffer[entry_offset];
144158d2fcdSBenno Rice outputter->output_entry(outfile, filename, entry,
145158d2fcdSBenno Rice platform_id, false);
146158d2fcdSBenno Rice }
147158d2fcdSBenno Rice }
148158d2fcdSBenno Rice
149158d2fcdSBenno Rice return (1 + (int)sh->num_section_entries[0]);
150158d2fcdSBenno Rice }
151158d2fcdSBenno Rice
152158d2fcdSBenno Rice static void
dump_eltorito(FILE * iso,const char * filename,FILE * outfile,struct outputter * outputter)153158d2fcdSBenno Rice dump_eltorito(FILE *iso, const char *filename, FILE *outfile,
154158d2fcdSBenno Rice struct outputter *outputter)
155158d2fcdSBenno Rice {
156158d2fcdSBenno Rice char buffer[ISO_DEFAULT_BLOCK_SIZE], *entry;
157158d2fcdSBenno Rice boot_volume_descriptor *bvd;
158158d2fcdSBenno Rice daddr_t boot_catalog;
159158d2fcdSBenno Rice size_t offset;
160158d2fcdSBenno Rice int entry_count;
161158d2fcdSBenno Rice
162158d2fcdSBenno Rice if (read_sector(iso, 17, buffer) != 0)
163158d2fcdSBenno Rice err(1, "failed to read from image");
164158d2fcdSBenno Rice
165158d2fcdSBenno Rice bvd = (boot_volume_descriptor *)buffer;
166158d2fcdSBenno Rice if (memcmp(bvd->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5) != 0)
167158d2fcdSBenno Rice warnx("%s: not a valid ISO", filename);
168*bfe6a0afSEd Maste if (bvd->boot_record_indicator[0] != ISO_VOLUME_DESCRIPTOR_BOOT ||
169*bfe6a0afSEd Maste memcmp(bvd->boot_system_identifier, ET_ID, 23) != 0)
170158d2fcdSBenno Rice warnx("%s: not an El Torito bootable ISO", filename);
171158d2fcdSBenno Rice
172158d2fcdSBenno Rice boot_catalog = isonum_731(bvd->boot_catalog_pointer);
173158d2fcdSBenno Rice
174158d2fcdSBenno Rice if (read_sector(iso, boot_catalog, buffer) != 0)
175158d2fcdSBenno Rice err(1, "failed to read from image");
176158d2fcdSBenno Rice
177158d2fcdSBenno Rice entry = buffer;
178158d2fcdSBenno Rice offset = 0;
179158d2fcdSBenno Rice
180158d2fcdSBenno Rice if (!boot_catalog_valid(entry))
181158d2fcdSBenno Rice warnx("%s: boot catalog checksum is invalid", filename);
182158d2fcdSBenno Rice
183158d2fcdSBenno Rice if (outputter->output_image != NULL)
184158d2fcdSBenno Rice outputter->output_image(outfile, filename, bvd);
185158d2fcdSBenno Rice
186158d2fcdSBenno Rice offset += ET_BOOT_ENTRY_SIZE;
187158d2fcdSBenno Rice entry = &buffer[offset];
188158d2fcdSBenno Rice if (outputter->output_entry != NULL)
189158d2fcdSBenno Rice outputter->output_entry(outfile, filename,
190158d2fcdSBenno Rice (boot_catalog_section_entry *)entry, 0, true);
191158d2fcdSBenno Rice
192158d2fcdSBenno Rice offset += ET_BOOT_ENTRY_SIZE;
193158d2fcdSBenno Rice
194158d2fcdSBenno Rice while (offset < ISO_DEFAULT_BLOCK_SIZE) {
195158d2fcdSBenno Rice entry = &buffer[offset];
196158d2fcdSBenno Rice
197158d2fcdSBenno Rice if ((uint8_t)entry[0] != ET_SECTION_HEADER_MORE &&
198158d2fcdSBenno Rice (uint8_t)entry[0] != ET_SECTION_HEADER_LAST)
199158d2fcdSBenno Rice break;
200158d2fcdSBenno Rice
201ddf77ec3SEd Maste entry_count = dump_section(buffer, sizeof(buffer), offset,
202ddf77ec3SEd Maste outfile, filename, outputter);
203158d2fcdSBenno Rice
204158d2fcdSBenno Rice offset += entry_count * ET_BOOT_ENTRY_SIZE;
205158d2fcdSBenno Rice }
206158d2fcdSBenno Rice }
207158d2fcdSBenno Rice
208158d2fcdSBenno Rice static void
usage(const char * progname)209158d2fcdSBenno Rice usage(const char *progname)
210158d2fcdSBenno Rice {
211158d2fcdSBenno Rice char *path;
212158d2fcdSBenno Rice
213158d2fcdSBenno Rice path = strdup(progname);
214158d2fcdSBenno Rice
215158d2fcdSBenno Rice fprintf(stderr, "usage: %s [-f format] [-o filename] filename [...]\n",
216158d2fcdSBenno Rice basename(path));
217158d2fcdSBenno Rice fprintf(stderr, "\tsupported output formats: shell, text\n");
218158d2fcdSBenno Rice exit(1);
219158d2fcdSBenno Rice }
220158d2fcdSBenno Rice
221158d2fcdSBenno Rice int
main(int argc,char ** argv)222158d2fcdSBenno Rice main(int argc, char **argv)
223158d2fcdSBenno Rice {
224158d2fcdSBenno Rice int ch, i;
225158d2fcdSBenno Rice FILE *outfile, *iso;
226158d2fcdSBenno Rice struct outputter *outputter;
227158d2fcdSBenno Rice
228158d2fcdSBenno Rice outfile = stdout;
229158d2fcdSBenno Rice outputter = output_text;
230158d2fcdSBenno Rice
231158d2fcdSBenno Rice static struct option longopts[] = {
232158d2fcdSBenno Rice { "format", required_argument, NULL, 'f' },
233158d2fcdSBenno Rice { "output", required_argument, NULL, 'o' },
234158d2fcdSBenno Rice { NULL, 0, NULL, 0 },
235158d2fcdSBenno Rice };
236158d2fcdSBenno Rice
237158d2fcdSBenno Rice while ((ch = getopt_long(argc, argv, "f:o:", longopts, NULL)) != -1) {
238158d2fcdSBenno Rice switch (ch) {
239158d2fcdSBenno Rice case 'f':
240158d2fcdSBenno Rice if (strcmp(optarg, "shell") == 0)
241158d2fcdSBenno Rice outputter = output_shell;
242158d2fcdSBenno Rice else if (strcmp(optarg, "text") == 0)
243158d2fcdSBenno Rice outputter = output_text;
244158d2fcdSBenno Rice else
245158d2fcdSBenno Rice usage(argv[0]);
246158d2fcdSBenno Rice break;
247158d2fcdSBenno Rice case 'o':
248158d2fcdSBenno Rice if (strcmp(optarg, "-") == 0) {
249158d2fcdSBenno Rice outfile = stdout;
250158d2fcdSBenno Rice } else if ((outfile = fopen(optarg, "w")) == NULL) {
251158d2fcdSBenno Rice err(1, "unable to open %s for output", optarg);
252158d2fcdSBenno Rice }
253158d2fcdSBenno Rice break;
254158d2fcdSBenno Rice default:
255158d2fcdSBenno Rice usage(argv[0]);
256158d2fcdSBenno Rice }
257158d2fcdSBenno Rice }
258158d2fcdSBenno Rice
259158d2fcdSBenno Rice argc -= optind;
260158d2fcdSBenno Rice argv += optind;
261158d2fcdSBenno Rice
262158d2fcdSBenno Rice for (i = 0; i < argc; i++) {
263158d2fcdSBenno Rice if (strcmp(argv[i], "-") == 0) {
264158d2fcdSBenno Rice iso = stdin;
265158d2fcdSBenno Rice } else {
266158d2fcdSBenno Rice iso = fopen(argv[i], "r");
267158d2fcdSBenno Rice if (iso == NULL)
268340cebe9SJessica Clarke err(1, "could not open %s", argv[i]);
269158d2fcdSBenno Rice }
270158d2fcdSBenno Rice dump_eltorito(iso, argv[i], outfile, outputter);
271158d2fcdSBenno Rice }
272158d2fcdSBenno Rice }
273