2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)isodump.c 1.27 05/05/15 joerg */
15 * File isodump.c - dump iso9660 directory information.
18 * Written by Eric Youngdale (1993).
20 * Copyright 1993 Yggdrasil Computing, Incorporated
21 * Copyright (c) 1999-2004 J. Schilling
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License version 2
25 * as published by the Free Software Foundation.
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License along with
33 * this program; see the file COPYING. If not, write to the Free Software
34 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
50 #include "../../wodim/defaults.h"
53 * XXX JS: Some structures have odd lengths!
54 * Some compilers (e.g. on Sun3/mc68020) padd the structures to even length.
55 * For this reason, we cannot use sizeof (struct iso_path_table) or
56 * sizeof (struct iso_directory_record) to compute on disk sizes.
57 * Instead, we use offsetof(..., name) and add the name size.
61 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
65 * Note: always use these macros to avoid problems.
67 * ISO_ROUND_UP(X) may cause an integer overflow and thus give
68 * incorrect results. So avoid it if possible.
70 * ISO_BLOCKS(X) is overflow safe. Prefer this when ever it is possible.
72 #define SECTOR_SIZE (2048)
73 #define ISO_ROUND_UP(X) (((X) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))
74 #define ISO_BLOCKS(X) (((X) / SECTOR_SIZE) + (((X)%SECTOR_SIZE)?1:0))
76 #define infile in_image
79 unsigned char buffer[2048];
80 unsigned char search[64];
83 #define PAGE sizeof (buffer)
85 #define ISODCL(from, to) (to - from + 1)
87 struct iso_primary_descriptor {
88 unsigned char type [ISODCL(1, 1)]; /* 711 */
89 unsigned char id [ISODCL(2, 6)];
90 unsigned char version [ISODCL(7, 7)]; /* 711 */
91 unsigned char unused1 [ISODCL(8, 8)];
92 unsigned char system_id [ISODCL(9, 40)]; /* aunsigned chars */
93 unsigned char volume_id [ISODCL(41, 72)]; /* dunsigned chars */
94 unsigned char unused2 [ISODCL(73, 80)];
95 unsigned char volume_space_size [ISODCL(81, 88)]; /* 733 */
96 unsigned char unused3 [ISODCL(89, 120)];
97 unsigned char volume_set_size [ISODCL(121, 124)]; /* 723 */
98 unsigned char volume_sequence_number [ISODCL(125, 128)]; /* 723 */
99 unsigned char logical_block_size [ISODCL(129, 132)]; /* 723 */
100 unsigned char path_table_size [ISODCL(133, 140)]; /* 733 */
101 unsigned char type_l_path_table [ISODCL(141, 144)]; /* 731 */
102 unsigned char opt_type_l_path_table [ISODCL(145, 148)]; /* 731 */
103 unsigned char type_m_path_table [ISODCL(149, 152)]; /* 732 */
104 unsigned char opt_type_m_path_table [ISODCL(153, 156)]; /* 732 */
105 unsigned char root_directory_record [ISODCL(157, 190)]; /* 9.1 */
106 unsigned char volume_set_id [ISODCL(191, 318)]; /* dunsigned chars */
107 unsigned char publisher_id [ISODCL(319, 446)]; /* achars */
108 unsigned char preparer_id [ISODCL(447, 574)]; /* achars */
109 unsigned char application_id [ISODCL(575, 702)]; /* achars */
110 unsigned char copyright_file_id [ISODCL(703, 739)]; /* 7.5 dchars */
111 unsigned char abstract_file_id [ISODCL(740, 776)]; /* 7.5 dchars */
112 unsigned char bibliographic_file_id [ISODCL(777, 813)]; /* 7.5 dchars */
113 unsigned char creation_date [ISODCL(814, 830)]; /* 8.4.26.1 */
114 unsigned char modification_date [ISODCL(831, 847)]; /* 8.4.26.1 */
115 unsigned char expiration_date [ISODCL(848, 864)]; /* 8.4.26.1 */
116 unsigned char effective_date [ISODCL(865, 881)]; /* 8.4.26.1 */
117 unsigned char file_structure_version [ISODCL(882, 882)]; /* 711 */
118 unsigned char unused4 [ISODCL(883, 883)];
119 unsigned char application_data [ISODCL(884, 1395)];
120 unsigned char unused5 [ISODCL(1396, 2048)];
123 struct iso_directory_record {
124 unsigned char length [ISODCL(1, 1)]; /* 711 */
125 unsigned char ext_attr_length [ISODCL(2, 2)]; /* 711 */
126 unsigned char extent [ISODCL(3, 10)]; /* 733 */
127 unsigned char size [ISODCL(11, 18)]; /* 733 */
128 unsigned char date [ISODCL(19, 25)]; /* 7 by 711 */
129 unsigned char flags [ISODCL(26, 26)];
130 unsigned char file_unit_size [ISODCL(27, 27)]; /* 711 */
131 unsigned char interleave [ISODCL(28, 28)]; /* 711 */
132 unsigned char volume_sequence_number [ISODCL(29, 32)]; /* 723 */
133 unsigned char name_len [ISODCL(33, 33)]; /* 711 */
134 unsigned char name [1];
137 static int isonum_731(char * p);
138 static int isonum_72(char * p);
139 static int isonum_723(char * p);
140 static int isonum_733(unsigned char * p);
141 static void reset_tty(void);
142 static void set_tty(void);
143 static void onsusp(int signo);
144 static void crsr2(int row, int col);
145 static int parse_rr(unsigned char * pnt, int len, int cont_flag);
146 static void dump_rr(struct iso_directory_record * idr);
147 static void showblock(int flag);
148 static int getbyte(void);
149 static void usage(int excode);
154 return ((p[0] & 0xff)
155 | ((p[1] & 0xff) << 8)
156 | ((p[2] & 0xff) << 16)
157 | ((p[3] & 0xff) << 24));
163 return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
170 if (p[0] != p[3] || p[1] != p[2]) {
172 comerrno(EX_BAD, "invalid format 7.2.3 number\n");
174 fprintf(stderr, "invalid format 7.2.3 number\n");
179 return (isonum_721(p));
184 isonum_733(unsigned char *p)
186 return (isonum_731((char *)p));
190 static struct sgttyb savetty;
191 static struct sgttyb newtty;
193 static struct termios savetty;
194 static struct termios newtty;
201 if (ioctl(STDIN_FILENO, TIOCSETN, &savetty) == -1) {
204 if (tcsetattr(STDIN_FILENO, TCSANOW, &savetty) == -1) {
206 if (ioctl(STDIN_FILENO, TCSETAF, &savetty) == -1) {
210 comerr("Cannot put tty into normal mode\n");
212 printf("Cannot put tty into normal mode\n");
222 if (ioctl(STDIN_FILENO, TIOCSETN, &newtty) == -1) {
225 if (tcsetattr(STDIN_FILENO, TCSANOW, &newtty) == -1) {
227 if (ioctl(STDIN_FILENO, TCSETAF, &newtty) == -1) {
231 comerr("Cannot put tty into raw mode\n");
233 printf("Cannot put tty into raw mode\n");
239 /* Come here when we get a suspend signal from the terminal */
245 /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
246 signal(SIGTTOU, SIG_IGN);
251 signal(SIGTTOU, SIG_DFL);
252 /* Send the TSTP signal to suspend our process group */
253 signal(SIGTSTP, SIG_DFL);
256 /* Pause for station break */
259 signal(SIGTSTP, onsusp);
267 crsr2(int row, int col)
269 printf("\033[%d;%dH", row, col);
273 parse_rr(unsigned char *pnt, int len, int cont_flag)
284 char symlinkname[1024];
288 /* printf(" RRlen=%d ", len); */
292 cont_extent = (off_t)0;
293 cont_offset = cont_size = 0;
302 printf("%c%c", pnt[0], pnt[1]);
303 if (pnt[3] != 1 && pnt[3] != 2) {
304 printf("**BAD RRVERSION (%d) for %c%c\n", pnt[3], pnt[0], pnt[1]);
305 return (0); /* JS ??? Is this right ??? */
306 } else if (pnt[0] == 'R' && pnt[1] == 'R') {
307 printf("=%d", pnt[3]);
310 if (pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
311 if (strncmp((char *)pnt, "PX", 2) == 0) flag2 |= 1;
312 if (strncmp((char *)pnt, "PN", 2) == 0) flag2 |= 2;
313 if (strncmp((char *)pnt, "SL", 2) == 0) flag2 |= 4;
314 if (strncmp((char *)pnt, "NM", 2) == 0) {
317 if ((pnt[4] & 6) != 0) {
320 memset(name, 0, sizeof (name));
321 memcpy(name, pnts, slen);
325 if (strncmp((char *)pnt, "CL", 2) == 0) flag2 |= 16;
326 if (strncmp((char *)pnt, "PL", 2) == 0) flag2 |= 32;
327 if (strncmp((char *)pnt, "RE", 2) == 0) flag2 |= 64;
328 if (strncmp((char *)pnt, "TF", 2) == 0) flag2 |= 128;
330 if (strncmp((char *)pnt, "PX", 2) == 0) {
331 extent = isonum_733(pnt+12);
332 printf("=%x", extent);
335 if (strncmp((char *)pnt, "CE", 2) == 0) {
336 cont_extent = (off_t)isonum_733(pnt+4);
337 cont_offset = isonum_733(pnt+12);
338 cont_size = isonum_733(pnt+20);
339 printf("=[%x,%x,%d]", (int)cont_extent, cont_offset,
343 if (strncmp((char *)pnt, "PL", 2) == 0 || strncmp((char *)pnt, "CL", 2) == 0) {
344 extent = isonum_733(pnt+4);
345 printf("=%x", extent);
348 if (strncmp((char *)pnt, "SL", 2) == 0) {
355 switch (pnts[0] & 0xfe) {
357 strncat(symlinkname, (char *)(pnts+2), pnts[1]);
360 strcat(symlinkname, ".");
363 strcat(symlinkname, "..");
366 if ((pnts[0] & 1) == 0)
367 strcat(symlinkname, "/");
370 strcat(symlinkname, "/mnt");
371 printf("Warning - mount point requested");
374 strcat(symlinkname, "kafka");
375 printf("Warning - host_name requested");
378 printf("Reserved bit setting in symlink");
382 if ((pnts[0] & 0xfe) && pnts[1] != 0) {
383 printf("Incorrect length in symlink component");
385 if ((pnts[0] & 1) == 0)
386 strcat(symlinkname, "/");
388 slen -= (pnts[1] + 2);
389 pnts += (pnts[1] + 2);
392 strcat(symlinkname, "+");
393 printf("=%s", symlinkname);
399 if (len <= 3 && cont_extent) {
400 unsigned char sector[2048];
403 readsecs(cont_extent * blocksize / 2048, sector, ISO_BLOCKS(sizeof (sector)));
405 lseek(fileno(infile), cont_extent * blocksize, SEEK_SET);
406 read(fileno(infile), sector, sizeof (sector));
408 flag2 |= parse_rr(§or[cont_offset], cont_size, 1);
413 if (!cont_flag && flag1 != flag2) {
414 printf("Flag %x != %x", flag1, flag2);
421 dump_rr(struct iso_directory_record *idr)
426 len = idr->length[0] & 0xff;
427 len -= offsetof(struct iso_directory_record, name[0]);
428 len -= idr->name_len[0];
429 pnt = (unsigned char *) idr;
430 pnt += offsetof(struct iso_directory_record, name[0]);
431 pnt += idr->name_len[0];
432 if ((idr->name_len[0] & 1) == 0) {
436 parse_rr(pnt, len, 0);
446 struct iso_directory_record *idr;
449 readsecs(file_addr / 2048, buffer, ISO_BLOCKS(sizeof (buffer)));
451 lseek(fileno(infile), file_addr, SEEK_SET);
452 read(fileno(infile), buffer, sizeof (buffer));
454 for (i = 0; i < 60; i++)
461 idr = (struct iso_directory_record *) &buffer[i];
462 if (idr->length[0] == 0)
464 printf("%3d ", idr->length[0]);
465 printf("[%2d] ", idr->volume_sequence_number[0]);
466 printf("%5x ", isonum_733(idr->extent));
467 printf("%8d ", isonum_733(idr->size));
468 printf("%02x/", idr->flags[0]);
469 printf((idr->flags[0] & 2) ? "*" : " ");
470 if (idr->name_len[0] == 1 && idr->name[0] == 0)
472 else if (idr->name_len[0] == 1 && idr->name[0] == 1)
475 for (j = 0; j < (int)idr->name_len[0]; j++) printf("%c", idr->name[j]);
476 for (j = 0; j < (14 - (int)idr->name_len[0]); j++) printf(" ");
481 if (i > 2048 - offsetof(struct iso_directory_record, name[0]))
487 if (sizeof (file_addr) > sizeof (long)) {
488 printf(" Zone, zone offset: %14llx %12.12llx ",
489 (Llong)file_addr / blocksize,
490 (Llong)file_addr & (Llong)(blocksize - 1));
492 printf(" Zone, zone offset: %6lx %4.4lx ",
493 (long) (file_addr / blocksize),
494 (long) file_addr & (blocksize - 1));
504 c1 = buffer[file_addr & (blocksize-1)];
506 if ((file_addr & (blocksize-1)) == 0)
514 errmsgno(EX_BAD, "Usage: %s [options] image\n",
517 fprintf(stderr, "Options:\n");
518 fprintf(stderr, "\t-help, -h Print this help\n");
519 fprintf(stderr, "\t-version Print version info and exit\n");
520 fprintf(stderr, "\t-i filename Filename to read ISO-9660 image from\n");
521 fprintf(stderr, "\tdev=target SCSI target to use as CD/DVD-Recorder\n");
522 fprintf(stderr, "\nIf neither -i nor dev= are speficied, <image> is needed.\n");
527 main(int argc, char *argv[])
531 char *opts = "help,h,version,i*,dev*";
534 char *filename = NULL;
535 char *devname = NULL;
538 struct iso_primary_descriptor ipd;
539 struct iso_directory_record *idr;
541 save_args(argc, argv);
545 if (getallargs(&cac, &cav, opts, &help, &help, &prvers,
546 &filename, &devname) < 0) {
547 errmsgno(EX_BAD, "Bad Option: '%s'\n", cav[0]);
553 printf("isodump %s (%s)\n", CDRKIT_VERSION, HOST_SYSTEM);
558 if (filename == NULL && devname == NULL) {
559 if (getfiles(&cac, &cav, opts) != 0) {
564 if (getfiles(&cac, &cav, opts) != 0) {
565 errmsgno(EX_BAD, "Bad Argument: '%s'\n", cav[0]);
568 if (filename != NULL && devname != NULL) {
569 errmsgno(EX_BAD, "Only one of -i or dev= allowed\n");
573 if (filename == NULL && devname == NULL)
574 cdr_defaults(&devname, NULL, NULL, NULL);
576 if (filename == NULL && devname == NULL) {
578 errmsgno(EX_BAD, "ISO-9660 image not specified\n");
580 fprintf(stderr, "ISO-9660 image not specified\n");
585 if (filename != NULL)
586 infile = fopen(filename, "rb");
590 if (infile != NULL) {
593 } else if (scsidev_open(filename) < 0) {
598 comerr("Cannot open '%s'\n", filename);
600 fprintf(stderr, "Cannot open '%s'\n", filename);
605 file_addr = (off_t) (16 << 11);
607 readsecs(file_addr / 2048, &ipd, ISO_BLOCKS(sizeof (ipd)));
609 lseek(fileno(infile), file_addr, SEEK_SET);
610 read(fileno(infile), &ipd, sizeof (ipd));
612 idr = (struct iso_directory_record *)ipd.root_directory_record;
614 blocksize = isonum_723((char *)ipd.logical_block_size);
615 if (blocksize != 512 && blocksize != 1024 && blocksize != 2048) {
619 file_addr = (off_t)isonum_733(idr->extent);
620 file_addr = file_addr * blocksize;
622 /* Now setup the keyboard for single character input. */
624 if (ioctl(STDIN_FILENO, TIOCGETP, &savetty) == -1) {
627 if (tcgetattr(STDIN_FILENO, &savetty) == -1) {
629 if (ioctl(STDIN_FILENO, TCGETA, &savetty) == -1) {
633 comerr("Stdin must be a tty\n");
635 printf("Stdin must be a tty\n");
641 newtty.sg_flags &= ~(ECHO|CRMOD);
642 newtty.sg_flags |= CBREAK;
644 newtty.c_lflag &= ~ICANON;
645 newtty.c_lflag &= ~ECHO;
646 newtty.c_cc[VMIN] = 1;
650 signal(SIGTSTP, onsusp);
652 on_comerr((void(*)(int, void *))reset_tty, NULL);
656 file_addr = (off_t)0;
658 read(STDIN_FILENO, &c, 1); /* FIXME: check return value */
660 file_addr -= blocksize;
662 file_addr += blocksize;
665 printf("Enter new starting block (in hex):");
666 if (sizeof (file_addr) > sizeof (long)) {
668 scanf("%llx", &ll); /* FIXME: check return value */
669 file_addr = (off_t)ll;
672 scanf("%lx", &l); /* FIXME: check return value */
673 file_addr = (off_t)l;
675 file_addr = file_addr * blocksize;
681 printf("Enter new search string:");
682 fgets((char *)search, sizeof (search), stdin); /* FIXME: check return value */
683 while (search[strlen((char *)search)-1] == '\n')
684 search[strlen((char *)search)-1] = 0;
697 slen = (int)strlen((char *)search);
698 for (i = 1; i < slen; i++) {
699 if (search[i] != getbyte())
705 file_addr &= ~(blocksize-1);