patch zlib check
[platform/upstream/cdrkit.git] / genisoimage / diag / isoinfo.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)isoinfo.c        1.50 05/05/15 joerg */
14 /* Parts from @(#)isoinfo.c     1.63 08/08/25 joerg */
15 /*
16  * File isodump.c - dump iso9660 directory information.
17  *
18  *
19  * Written by Eric Youngdale (1993).
20  *
21  * Copyright 1993 Yggdrasil Computing, Incorporated
22  * Copyright (c) 1999-2004 J. Schilling
23  *
24  * This program is free software; you can redistribute it and/or modify
25  * it under the terms of the GNU General Public License version 2
26  * as published by the Free Software Foundation.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License along with
34  * this program; see the file COPYING.  If not, write to the Free Software
35  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36  */
37
38 /*
39  * Simple program to dump contents of iso9660 image in more usable format.
40  *
41  * Usage:
42  * To list contents of image (with or without RR):
43  *      isoinfo -l [-R] -i imagefile
44  * To extract file from image:
45  *      isoinfo -i imagefile -x xtractfile > outfile
46  * To generate a "find" like list of files:
47  *      isoinfo -f -i imagefile
48  */
49
50 #include <mconfig.h>
51 #include <stdxlib.h>
52 #include <unixstd.h>
53 #include <strdefs.h>
54
55 #include <stdio.h>
56 #include <utypes.h>
57 #include <standard.h>
58 #include <signal.h>
59 #include <sys/stat.h>
60 #include <statdefs.h>
61 #include <fctldefs.h>
62 #include <schily.h>
63
64 #include "../iso9660.h"
65 #include "../scsi.h"
66 #include "../../wodim/defaults.h"
67
68 #include <unls.h>
69
70 #if     defined(__CYGWIN32__) || defined(__EMX__) || defined(__DJGPP__)
71 #include <io.h>                                 /* for setmode() prototype */
72 #endif
73
74 /*
75  * Make sure we have a definition for this.  If not, take a very conservative
76  * guess.
77  * POSIX requires the max pathname component lenght to be defined in limits.h
78  * If variable, it may be undefined. If undefined, there should be
79  * a definition for _POSIX_NAME_MAX in limits.h or in unistd.h
80  * As _POSIX_NAME_MAX is defined to 14, we cannot use it.
81  * XXX Eric's wrong comment:
82  * XXX From what I can tell SunOS is the only one with this trouble.
83  */
84 #ifdef  HAVE_LIMITS_H
85 #include <limits.h>
86 #endif
87 #ifndef NAME_MAX
88 #ifdef  FILENAME_MAX
89 #define NAME_MAX        FILENAME_MAX
90 #else
91 #define NAME_MAX        256
92 #endif
93 #endif
94
95 #ifndef PATH_MAX
96 #ifdef  FILENAME_MAX
97 #define PATH_MAX        FILENAME_MAX
98 #else
99 #define PATH_MAX        1024
100 #endif
101 #endif
102
103 /*
104  * XXX JS: Some structures have odd lengths!
105  * Some compilers (e.g. on Sun3/mc68020) padd the structures to even length.
106  * For this reason, we cannot use sizeof (struct iso_path_table) or
107  * sizeof (struct iso_directory_record) to compute on disk sizes.
108  * Instead, we use offsetof(..., name) and add the name size.
109  * See iso9660.h
110  */
111 #ifndef offsetof
112 #define offsetof(TYPE, MEMBER)  ((size_t) &((TYPE *)0)->MEMBER)
113 #endif
114
115 #ifndef S_ISLNK
116 #define S_ISLNK(m)      (((m) & S_IFMT) == S_IFLNK)
117 #endif
118 #ifndef S_ISSOCK
119 #ifdef  S_IFSOCK
120 #       define  S_ISSOCK(m)     (((m) & S_IFMT) == S_IFSOCK)
121 #else
122 #       define  S_ISSOCK(m)     (0)
123 #endif
124 #endif
125
126 /*
127  * Note: always use these macros to avoid problems.
128  *
129  * ISO_ROUND_UP(X)      may cause an integer overflow and thus give
130  *                      incorrect results. So avoid it if possible.
131  *
132  * ISO_BLOCKS(X)        is overflow safe. Prefer this when ever it is possible.
133  */
134 #define SECTOR_SIZE     (2048)
135 #define ISO_ROUND_UP(X) (((X) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))
136 #define ISO_BLOCKS(X)   (((X) / SECTOR_SIZE) + (((X)%SECTOR_SIZE)?1:0))
137
138 #define infile  in_image
139 FILE    *infile = NULL;
140 int     use_rock = 0;
141 int     use_joliet = 0;
142 int     do_listing = 0;
143 int     do_find = 0;
144 int     do_sectors = 0;
145 int     do_pathtab = 0;
146 int     do_pvd = 0;
147 BOOL    debug = FALSE;
148 char    *xtract = 0;
149 int     su_version = 0;
150 int     aa_version = 0;
151 int     ucs_level = 0;
152
153 struct stat     fstat_buf;
154 int             found_rr;
155 char            name_buf[256];
156 char            xname[2048];
157 unsigned char   date_buf[9];
158 /*
159  * Use sector_offset != 0 (-N #) if we have an image file
160  * of a single session and we need to list the directory contents.
161  * This is the session block (sector) number of the start
162  * of the session when it would be on disk.
163  */
164 unsigned int    sector_offset = 0;
165
166 unsigned char   buffer[2048];
167
168 struct unls_table *unls;
169
170 #define PAGE sizeof (buffer)
171
172 #define ISODCL(from, to) (to - from + 1)
173
174
175 int     isonum_721(char * p);
176 int     isonum_723(char * p);
177 int     isonum_731(char * p);
178 int     isonum_732(char * p);
179 int     isonum_733(unsigned char * p);
180 void    printchars(char *s, int n);
181 char    *sdate(char *dp);
182 void    dump_pathtab(int block, int size);
183 int     parse_rr(unsigned char * pnt, int len, int cont_flag);
184 void    find_rr(struct iso_directory_record * idr, Uchar **pntp, int *lenp);
185 int     dump_rr(struct iso_directory_record * idr);
186 void    dump_stat(struct iso_directory_record * idr, int extent);
187 void    extract_file(struct iso_directory_record * idr);
188 void    parse_dir(char * rootname, int extent, int len);
189 void    usage(int excode);
190
191 static  void    printf_bootinfo(FILE *f, int bootcat_offset);
192 static  char    *arch_name(int val);
193 static  char    *boot_name(int val);
194 static  char    *bootmedia_name(int val);
195
196
197 int
198 isonum_721(char *p)
199 {
200         return ((p[0] & 0xff)
201                 | ((p[1] & 0xff) << 8));
202 }
203
204 int
205 isonum_723(char *p)
206 {
207 #if 0
208         if (p[0] != p[3] || p[1] != p[2]) {
209 #ifdef  USE_LIBSCHILY
210                 comerrno(EX_BAD, "invalid format 7.2.3 number\n");
211 #else
212                 fprintf(stderr, "invalid format 7.2.3 number\n");
213                 exit(1);
214 #endif
215         }
216 #endif
217         return (isonum_721(p));
218 }
219
220 int
221 isonum_731(char *p)
222 {
223         return ((p[0] & 0xff)
224                 | ((p[1] & 0xff) << 8)
225                 | ((p[2] & 0xff) << 16)
226                 | ((p[3] & 0xff) << 24));
227 }
228
229 int
230 isonum_732(char *p)
231 {
232         return ((p[3] & 0xff)
233                 | ((p[2] & 0xff) << 8)
234                 | ((p[1] & 0xff) << 16)
235                 | ((p[0] & 0xff) << 24));
236 }
237
238 int
239 isonum_733(unsigned char *p)
240 {
241         return (isonum_731((char *)p));
242 }
243
244 void
245 printchars(char *s, int n)
246 {
247         int     i;
248         char    *p;
249
250         for (; n > 0 && *s; n--) {
251                 if (*s == ' ') {
252                         p = s;
253                         i = n;
254                         while (--i >= 0 && *p++ == ' ')
255                                 ;
256                         if (i <= 0)
257                                 break;
258                 }
259                 putchar(*s++);
260         }
261 }
262
263 /*
264  * Print date info from PVD
265  */
266 char *
267 sdate(char *dp)
268 {
269         static  char    d[30];
270
271         sprintf(d, "%4.4s %2.2s %2.2s %2.2s:%2.2s:%2.2s.%2.2s",
272                         &dp[0],         /* Year */
273                         &dp[4],         /* Month */
274                         &dp[6],         /* Monthday */
275                         &dp[8],         /* Hour */
276                         &dp[10],        /* Minute */
277                         &dp[12],        /* Seconds */
278                         &dp[14]);       /* Hunreds of a Seconds */
279
280         /*
281          * dp[16] contains minute offset from Greenwich
282          * Positive values are to the east of Greenwich.
283          */
284         return (d);
285 }
286
287 void
288 dump_pathtab(int block, int size)
289 {
290         unsigned char   *buf;
291         int             offset;
292         int             idx;
293         int             extent;
294         int             pindex;
295         int             j;
296         int             len;
297         int             jlen;
298         char            namebuf[255];
299         unsigned char   uh, ul, uc, *up;
300
301
302         printf("Path table starts at block %d, size %d\n", block, size);
303
304         buf = (unsigned char *) malloc(ISO_ROUND_UP(size));
305
306 #ifdef  USE_SCG
307         readsecs(block - sector_offset, buf, ISO_BLOCKS(size));
308 #else
309         lseek(fileno(infile), ((off_t)(block - sector_offset)) << 11, SEEK_SET);
310         read(fileno(infile), buf, size);
311 #endif
312
313         offset = 0;
314         idx = 1;
315         while (offset < size) {
316                 len    = buf[offset];
317                 extent = isonum_731((char *)buf + offset + 2);
318                 pindex  = isonum_721((char *)buf + offset + 6);
319                 switch (ucs_level) {
320                 case 3:
321                 case 2:
322                 case 1:
323                         jlen = len/2;
324                         namebuf[0] = '\0';
325                         for (j = 0; j < jlen; j++) {
326                                 uh = buf[offset + 8 + j*2];
327                                 ul = buf[offset + 8 + j*2+1];
328
329                                 up = unls->unls_uni2cs[uh];
330
331                                 if (up == NULL)
332                                         uc = '\0';
333                                 else
334                                         uc = up[ul];
335
336                                 namebuf[j] = uc ? uc : '_';
337                         }
338                         printf("%4d: %4d %x %.*s\n",
339                                 idx, pindex, extent, jlen, namebuf);
340                         break;
341                 case 0:
342                         printf("%4d: %4d %x %.*s\n",
343                                 idx, pindex, extent, len, buf + offset + 8);
344                 }
345
346                 idx++;
347                 offset += 8 + len;
348                 if (offset & 1)
349                         offset++;
350         }
351
352         free(buf);
353 }
354
355 int
356 parse_rr(unsigned char *pnt, int len, int cont_flag)
357 {
358         int slen;
359         int xlen;
360         int ncount;
361         int extent;
362         int cont_extent, cont_offset, cont_size;
363         int flag1, flag2;
364         unsigned char *pnts;
365         char symlinkname[1024];
366         int goof;
367
368         symlinkname[0] = 0;
369
370         cont_extent = cont_offset = cont_size = 0;
371
372         ncount = 0;
373         flag1 = flag2 = 0;
374         while (len >= 4) {
375                 if (pnt[3] != 1 && pnt[3] != 2) {
376                         printf("**BAD RRVERSION (%d)\n", pnt[3]);
377                         return (0);             /* JS ??? Is this right ??? */
378                 }
379                 ncount++;
380                 if (pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
381                 if (strncmp((char *)pnt, "PX", 2) == 0) flag2 |= 1;     /* POSIX attributes */
382                 if (strncmp((char *)pnt, "PN", 2) == 0) flag2 |= 2;     /* POSIX device number */
383                 if (strncmp((char *)pnt, "SL", 2) == 0) flag2 |= 4;     /* Symlink */
384                 if (strncmp((char *)pnt, "NM", 2) == 0) flag2 |= 8;     /* Alternate Name */
385                 if (strncmp((char *)pnt, "CL", 2) == 0) flag2 |= 16;    /* Child link */
386                 if (strncmp((char *)pnt, "PL", 2) == 0) flag2 |= 32;    /* Parent link */
387                 if (strncmp((char *)pnt, "RE", 2) == 0) flag2 |= 64;    /* Relocated Direcotry */
388                 if (strncmp((char *)pnt, "TF", 2) == 0) flag2 |= 128;   /* Time stamp */
389                 if (strncmp((char *)pnt, "SP", 2) == 0) {
390                         flag2 |= 1024;                                  /* SUSP record */
391                         su_version = pnt[3] & 0xff;
392                 }
393                 if (strncmp((char *)pnt, "AA", 2) == 0) {
394                         flag2 |= 2048;                                  /* Apple Signature record */
395                         aa_version = pnt[3] & 0xff;
396                 }
397
398                 if (strncmp((char *)pnt, "PX", 2) == 0) {               /* POSIX attributes */
399                         fstat_buf.st_mode = isonum_733(pnt+4);
400                         fstat_buf.st_nlink = isonum_733(pnt+12);
401                         fstat_buf.st_uid = isonum_733(pnt+20);
402                         fstat_buf.st_gid = isonum_733(pnt+28);
403                 }
404
405                 if (strncmp((char *)pnt, "NM", 2) == 0) {               /* Alternate Name */
406                         int     l = strlen(name_buf);
407
408                         if (!found_rr)
409                                 l = 0;
410                         strncpy(&name_buf[l], (char *)(pnt+5), pnt[2] - 5);
411                         name_buf[l + pnt[2] - 5] = 0;
412                         found_rr = 1;
413                 }
414
415                 if (strncmp((char *)pnt, "CE", 2) == 0) {               /* Continuation Area */
416                         cont_extent = isonum_733(pnt+4);
417                         cont_offset = isonum_733(pnt+12);
418                         cont_size = isonum_733(pnt+20);
419                 }
420
421                 if (strncmp((char *)pnt, "PL", 2) == 0 || strncmp((char *)pnt, "CL", 2) == 0) {
422                         extent = isonum_733(pnt+4);
423                 }
424
425                 if (strncmp((char *)pnt, "SL", 2) == 0) {               /* Symlink */
426                         int     cflag;
427
428                         cflag = pnt[4];
429                         pnts = pnt+5;
430                         slen = pnt[2] - 5;
431                         while (slen >= 1) {
432                                 switch (pnts[0] & 0xfe) {
433                                 case 0:
434                                         strncat(symlinkname, (char *)(pnts+2), pnts[1]);
435                                         symlinkname[pnts[1]] = 0;
436                                         break;
437                                 case 2:
438                                         strcat(symlinkname, ".");
439                                         break;
440                                 case 4:
441                                         strcat(symlinkname, "..");
442                                         break;
443                                 case 8:
444                                         strcat(symlinkname, "/");
445                                         break;
446                                 case 16:
447                                         strcat(symlinkname, "/mnt");
448                                         printf("Warning - mount point requested");
449                                         break;
450                                 case 32:
451                                         strcat(symlinkname, "kafka");
452                                         printf("Warning - host_name requested");
453                                         break;
454                                 default:
455                                         printf("Reserved bit setting in symlink");
456                                         goof++;
457                                         break;
458                                 }
459                                 if ((pnts[0] & 0xfe) && pnts[1] != 0) {
460                                         printf("Incorrect length in symlink component");
461                                 }
462                                 if (xname[0] == 0) strcpy(xname, "-> ");
463                                 strcat(xname, symlinkname);
464                                 symlinkname[0] = 0;
465                                 xlen = strlen(xname);
466                                 if ((pnts[0] & 1) == 0 && xname[xlen-1] != '/') strcat(xname, "/");
467
468                                 slen -= (pnts[1] + 2);
469                                 pnts += (pnts[1] + 2);
470                         }
471                         symlinkname[0] = 0;
472                 }
473
474                 len -= pnt[2];
475                 pnt += pnt[2];
476                 if (len <= 3 && cont_extent) {
477                         unsigned char   sector[2048];
478
479 #ifdef  USE_SCG
480                         readsecs(cont_extent - sector_offset, sector, ISO_BLOCKS(sizeof (sector)));
481 #else
482                         lseek(fileno(infile), ((off_t)(cont_extent - sector_offset)) << 11, SEEK_SET);
483                         read(fileno(infile), sector, sizeof (sector));
484 #endif
485                         flag2 |= parse_rr(&sector[cont_offset], cont_size, 1);
486                 }
487         }
488         /*
489          * for symbolic links, strip out the last '/'
490          */
491         if (xname[0] != 0 && xname[strlen(xname)-1] == '/') {
492                 xname[strlen(xname)-1] = '\0';
493         }
494         return (flag2);
495 }
496
497 void
498 find_rr(struct iso_directory_record *idr, Uchar **pntp, int *lenp)
499 {
500         struct iso_xa_dir_record *xadp;
501         int len;
502         unsigned char * pnt;
503
504         len = idr->length[0] & 0xff;
505         len -= offsetof(struct iso_directory_record, name[0]);
506         len -= idr->name_len[0];
507
508         pnt = (unsigned char *) idr;
509         pnt += offsetof(struct iso_directory_record, name[0]);
510         pnt += idr->name_len[0];
511         if ((idr->name_len[0] & 1) == 0) {
512                 pnt++;
513                 len--;
514         }
515         if (len >= 14) {
516                 xadp = (struct iso_xa_dir_record *)pnt;
517
518                 if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
519                     xadp->reserved[0] == '\0') {
520                         len -= 14;
521                         pnt += 14;
522                 }
523         }
524         *pntp = pnt;
525         *lenp = len;
526 }
527
528 int
529 dump_rr(struct iso_directory_record *idr)
530 {
531         int len;
532         unsigned char * pnt;
533
534         find_rr(idr, &pnt, &len);
535         return (parse_rr(pnt, len, 0));
536 }
537
538 struct todo
539 {
540         struct todo     *next;
541         char            *name;
542         int             extent;
543         int             length;
544 };
545
546 struct todo     *todo_idr = NULL;
547
548 char            *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
549                                 "Aug", "Sep", "Oct", "Nov", "Dec"};
550
551 void
552 dump_stat(struct iso_directory_record *idr, int extent)
553 {
554         int     i;
555         char    outline[80];
556
557         memset(outline, ' ', sizeof (outline));
558
559         if (S_ISREG(fstat_buf.st_mode))
560                 outline[0] = '-';
561         else if (S_ISDIR(fstat_buf.st_mode))
562                 outline[0] = 'd';
563         else if (S_ISLNK(fstat_buf.st_mode))
564                 outline[0] = 'l';
565         else if (S_ISCHR(fstat_buf.st_mode))
566                 outline[0] = 'c';
567         else if (S_ISBLK(fstat_buf.st_mode))
568                 outline[0] = 'b';
569         else if (S_ISFIFO(fstat_buf.st_mode))
570                 outline[0] = 'f';
571         else if (S_ISSOCK(fstat_buf.st_mode))
572                 outline[0] = 's';
573         else
574                 outline[0] = '?';
575
576         memset(outline+1, '-', 9);
577         if (fstat_buf.st_mode & S_IRUSR)
578                 outline[1] = 'r';
579         if (fstat_buf.st_mode & S_IWUSR)
580                 outline[2] = 'w';
581         if (fstat_buf.st_mode & S_IXUSR)
582                 outline[3] = 'x';
583
584         if (fstat_buf.st_mode & S_IRGRP)
585                 outline[4] = 'r';
586         if (fstat_buf.st_mode & S_IWGRP)
587                 outline[5] = 'w';
588         if (fstat_buf.st_mode & S_IXGRP)
589                 outline[6] = 'x';
590
591         if (fstat_buf.st_mode & S_IROTH)
592                 outline[7] = 'r';
593         if (fstat_buf.st_mode & S_IWOTH)
594                 outline[8] = 'w';
595         if (fstat_buf.st_mode & S_IXOTH)
596                 outline[9] = 'x';
597
598         /*
599          * XXX This is totally ugly code from Eric.
600          * XXX If one field is wider than expected then it is truncated.
601          */
602         sprintf(outline+11, "%3ld", (long)fstat_buf.st_nlink);
603         sprintf(outline+15, "%4lo", (unsigned long)fstat_buf.st_uid);
604         sprintf(outline+20, "%4lo", (unsigned long)fstat_buf.st_gid);
605         sprintf(outline+30, "%10lld", (Llong)fstat_buf.st_size);
606
607         if (do_sectors == 0) {
608                 sprintf(outline+30, "%10lld", (Llong)fstat_buf.st_size);
609         } else {
610                 sprintf(outline+30, "%10lld", (Llong)((fstat_buf.st_size+PAGE-1)/PAGE));
611         }
612
613         if (date_buf[1] >= 1 && date_buf[1] <= 12) {
614                 memcpy(outline+41, months[date_buf[1]-1], 3);
615         }
616
617         sprintf(outline+45, "%2d", date_buf[2]);
618                 outline[63] = 0;
619         sprintf(outline+48, "%4d", date_buf[0]+1900);
620
621         sprintf(outline+53, "[%7d", extent);    /* XXX up to 20 GB */
622         sprintf(outline+61, " %02X]", idr->flags[0] & 0xFF);
623
624         for (i = 0; i < 66; i++) {
625                 if (outline[i] == 0) outline[i] = ' ';
626         }
627         outline[66] = 0;
628         printf("%s %s %s\n", outline, name_buf, xname);
629 }
630
631 void
632 extract_file(struct iso_directory_record *idr)
633 {
634         int             extent, len, tlen;
635         unsigned char   buff[2048];
636
637 #if     defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__EMX__) || defined(__DJGPP__)
638         setmode(fileno(stdout), O_BINARY);
639 #endif
640
641         extent = isonum_733((unsigned char *)idr->extent);
642         len = isonum_733((unsigned char *)idr->size);
643
644         while (len > 0) {
645 #ifdef  USE_SCG
646                 readsecs(extent - sector_offset, buff, ISO_BLOCKS(sizeof (buff)));
647                 tlen = (len > sizeof (buff) ? sizeof (buff) : len);
648 #else
649                 lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET);
650                 tlen = (len > sizeof (buff) ? sizeof (buff) : len);
651                 read(fileno(infile), buff, tlen);
652 #endif
653                 len -= tlen;
654                 extent++;
655                 write(STDOUT_FILENO, buff, tlen); /* FIXME: check return value */
656         }
657 }
658
659 void
660 parse_dir(char *rootname, int extent, int len)
661 {
662         char            testname[PATH_MAX+1];
663         struct todo     *td;
664         int             i;
665         struct iso_directory_record * idr;
666         unsigned char   uh, ul, uc, *up;
667         unsigned char   flags = 0;
668         Llong           size = 0;
669         int             sextent = 0;
670
671
672         if (do_listing)
673                 printf("\nDirectory listing of %s\n", rootname);
674
675         while (len > 0) {
676 #ifdef  USE_SCG
677                 readsecs(extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer)));
678 #else
679                 lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET);
680                 read(fileno(infile), buffer, sizeof (buffer));
681 #endif
682                 len -= sizeof (buffer);
683                 extent++;
684                 i = 0;
685                 while (1 == 1) {
686                         idr = (struct iso_directory_record *) &buffer[i];
687                         if (idr->length[0] == 0) break;
688                         memset(&fstat_buf, 0, sizeof (fstat_buf));
689                         found_rr = 0;
690                         name_buf[0] = xname[0] = 0;
691                         fstat_buf.st_size = (off_t)(unsigned)isonum_733((unsigned char *)idr->size);
692                         if (idr->flags[0] & 2)
693                                 fstat_buf.st_mode |= S_IFDIR;
694                         else
695                                 fstat_buf.st_mode |= S_IFREG;
696                         if (idr->name_len[0] == 1 && idr->name[0] == 0)
697                                 strcpy(name_buf, ".");
698                         else if (idr->name_len[0] == 1 && idr->name[0] == 1)
699                                 strcpy(name_buf, "..");
700                         else {
701                                 switch (ucs_level) {
702                                 case 3:
703                                 case 2:
704                                 case 1:
705                                         /*
706                                          * Unicode name.  Convert as best we can.
707                                          */
708                                         {
709                                         int     j;
710
711                                         name_buf[0] = '\0';
712                                         for (j = 0; j < (int)idr->name_len[0] / 2; j++) {
713                                                 uh = idr->name[j*2];
714                                                 ul = idr->name[j*2+1];
715
716                                                 up = unls->unls_uni2cs[uh];
717
718                                                 if (up == NULL)
719                                                         uc = '\0';
720                                                 else
721                                                         uc = up[ul];
722
723                                                 name_buf[j] = uc ? uc : '_';
724                                         }
725                                         name_buf[idr->name_len[0]/2] = '\0';
726                                         }
727                                         break;
728                                 case 0:
729                                         /*
730                                          * Normal non-Unicode name.
731                                          */
732                                         strncpy(name_buf, idr->name, idr->name_len[0]);
733                                         name_buf[idr->name_len[0]] = 0;
734                                         break;
735                                 default:
736                                         /*
737                                          * Don't know how to do these yet.  Maybe they are the same
738                                          * as one of the above.
739                                          */
740                                         exit(1);
741                                 }
742                         }
743                         memcpy(date_buf, idr->date, 9);
744                         if (use_rock)
745                                 dump_rr(idr);
746                         if ((idr->flags[0] & 2) != 0 &&
747                             (idr->name_len[0] != 1 ||
748                             (idr->name[0] != 0 && idr->name[0] != 1))) {
749                                 /*
750                                  * Add this directory to the todo list.
751                                  */
752                                 td = todo_idr;
753                                 if (td != NULL) {
754                                         while (td->next != NULL)
755                                                 td = td->next;
756                                         td->next = (struct todo *) malloc(sizeof (*td));
757                                         td = td->next;
758                                 } else {
759                                         todo_idr = td = (struct todo *) malloc(sizeof (*td));
760                                 }
761                                 td->next = NULL;
762                                 td->extent = isonum_733((unsigned char *)idr->extent);
763                                 td->length = isonum_733((unsigned char *)idr->size);
764                                 td->name = (char *) malloc(strlen(rootname)
765                                                                 + strlen(name_buf) + 2);
766                                 strcpy(td->name, rootname);
767                                 strcat(td->name, name_buf);
768                                 strcat(td->name, "/");
769                         } else {
770                                 strcpy(testname, rootname);
771                                 strcat(testname, name_buf);
772                                 if (xtract && strcmp(xtract, testname) == 0) {
773                                         extract_file(idr);
774                                 }
775                         }
776                         if (do_find &&
777                             (idr->name_len[0] != 1 ||
778                             (idr->name[0] != 0 && idr->name[0] != 1))) {
779                                 strcpy(testname, rootname);
780                                 strcat(testname, name_buf);
781                                 printf("%s\n", testname);
782                         }
783                         if (do_listing) {
784                                 if ((idr->flags[0] & ISO_MULTIEXTENT) && size == 0)
785                                         sextent = isonum_733((unsigned char *)idr->extent);
786                                 if (debug ||
787                                     ((idr->flags[0] & ISO_MULTIEXTENT) == 0 && size == 0)) {
788                                         dump_stat(idr, isonum_733((unsigned char *)idr->extent));
789                                 }
790                                 size += fstat_buf.st_size;
791                                 if ((flags & ISO_MULTIEXTENT) &&
792                                     (idr->flags[0] & ISO_MULTIEXTENT) == 0) {
793                                         fstat_buf.st_size = size;
794                                         if (!debug)
795                                                 idr->flags[0] |= ISO_MULTIEXTENT;
796                                         dump_stat(idr, sextent);
797                                         if (!debug)
798                                                 idr->flags[0] &= ~ISO_MULTIEXTENT;
799                                 }
800                                 flags = idr->flags[0];
801                                 if ((idr->flags[0] & ISO_MULTIEXTENT) == 0)
802                                         size = 0;
803                         }
804                         i += buffer[i];
805                         if (i > 2048 - offsetof(struct iso_directory_record, name[0])) break;
806                 }
807         }
808 }
809
810 void
811 usage(int excode)
812 {
813         errmsgno(EX_BAD, "Usage: %s [options] -i filename\n", get_progname());
814
815         fprintf(stderr, "Options:\n");
816         fprintf(stderr, "\t-help,-h     Print this help\n");
817         fprintf(stderr, "\t-version     Print version info and exit\n");
818         fprintf(stderr, "\t-debug               Print additional debug info\n");
819         fprintf(stderr, "\t-d           Print information from the primary volume descriptor\n");
820         fprintf(stderr, "\t-f           Generate output similar to 'find .  -print'\n");
821         fprintf(stderr, "\t-J           Print information from Joliet extensions\n");
822         fprintf(stderr, "\t-j charset   Use charset to display Joliet file names\n");
823         fprintf(stderr, "\t-l           Generate output similar to 'ls -lR'\n");
824         fprintf(stderr, "\t-p           Print Path Table\n");
825         fprintf(stderr, "\t-R           Print information from Rock Ridge extensions\n");
826         fprintf(stderr, "\t-s           Print file size infos in multiples of sector size (%ld bytes).\n", (long)PAGE);
827         fprintf(stderr, "\t-N sector    Sector number where ISO image should start on CD\n");
828         fprintf(stderr, "\t-T sector    Sector number where actual session starts on CD\n");
829         fprintf(stderr, "\t-i filename  Filename to read ISO-9660 image from\n");
830         fprintf(stderr, "\tdev=target   SCSI target to use as CD/DVD-Recorder\n");
831         fprintf(stderr, "\t-x pathname  Extract specified file to stdout\n");
832         exit(excode);
833 }
834
835 int
836 main(int argc, char *argv[])
837 {
838         int     cac;
839         char    * const *cav;
840         int     c;
841         char    * filename = NULL;
842         char    * devname = NULL;
843         /*
844          * Use toc_offset != 0 (-T #) if we have a complete multi-session
845          * disc that we want/need to play with.
846          * Here we specify the offset where we want to
847          * start searching for the TOC.
848          */
849         int     toc_offset = 0;
850         int     extent;
851         struct todo * td;
852         struct iso_primary_descriptor ipd;
853         struct iso_primary_descriptor jpd;
854         struct eltorito_boot_descriptor bpd;
855         struct iso_directory_record * idr;
856         char    *charset = NULL;
857         char    *opts = "help,h,version,debug,d,p,i*,dev*,J,R,l,x*,f,s,N#l,T#l,j*";
858         BOOL    help = FALSE;
859         BOOL    prvers = FALSE;
860         BOOL    found_eltorito = FALSE;
861         int     bootcat_offset = 0;
862
863
864         save_args(argc, argv);
865
866         cac = argc - 1;
867         cav = argv + 1;
868         if (getallargs(&cac, &cav, opts,
869                                 &help, &help, &prvers, &debug,
870                                 &do_pvd, &do_pathtab,
871                                 &filename, &devname,
872                                 &use_joliet, &use_rock,
873                                 &do_listing,
874                                 &xtract,
875                                 &do_find, &do_sectors,
876                                 &sector_offset, &toc_offset,
877                                 &charset) < 0) {
878                 errmsgno(EX_BAD, "Bad Option: '%s'\n", cav[0]);
879                 usage(EX_BAD);
880         }
881         if (help)
882                 usage(0);
883         if (prvers) {
884                 printf("isoinfo %s (%s)\n", CDRKIT_VERSION, HOST_SYSTEM);
885                 exit(0);
886         }
887         cac = argc - 1;
888         cav = argv + 1;
889         if (getfiles(&cac, &cav, opts) != 0) {
890                 errmsgno(EX_BAD, "Bad Argument: '%s'\n", cav[0]);
891                 usage(EX_BAD);
892         }
893
894         init_unls();            /* Initialize UNICODE tables */
895         init_unls_file(charset);
896         if (charset == NULL) {
897 #if     (defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__DJGPP__)) && !defined(IS_CYGWIN_1)
898                 unls = load_unls("cp437");
899 #else
900                 unls = load_unls("iso8859-1");
901 #endif
902         } else {
903                 if (strcmp(charset, "default") == 0)
904                         unls = load_unls_default();
905                 else
906                         unls = load_unls(charset);
907         }
908         if (unls == NULL) {     /* Unknown charset specified */
909                 fprintf(stderr, "Unknown charset: %s\nKnown charsets are:\n",
910                                                         charset);
911                 list_unls();    /* List all known charset names */
912                 exit(1);
913         }
914
915         if (filename != NULL && devname != NULL) {
916                 errmsgno(EX_BAD, "Only one of -i or dev= allowed\n");
917                 usage(EX_BAD);
918         }
919 #ifdef  USE_SCG
920         if (filename == NULL && devname == NULL)
921                 cdr_defaults(&devname, NULL, NULL, NULL);
922 #endif
923         if (filename == NULL && devname == NULL) {
924 #ifdef  USE_LIBSCHILY
925                 errmsgno(EX_BAD, "ISO-9660 image not specified\n");
926 #else
927                 fprintf(stderr, "ISO-9660 image not specified\n");
928 #endif
929                 usage(EX_BAD);
930         }
931
932         if (filename != NULL)
933                 infile = fopen(filename, "rb");
934         else
935                 filename = devname;
936
937         if (infile != NULL) {
938                 /* EMPTY */;
939 #ifdef  USE_SCG
940         } else if (scsidev_open(filename) < 0) {
941 #else
942         } else {
943 #endif
944 #ifdef  USE_LIBSCHILY
945                 comerr("Unable to open %s\n", filename);
946 #else
947                 fprintf(stderr, "Unable to open %s\n", filename);
948                 exit(1);
949 #endif
950         }
951
952         /*
953          * Absolute sector offset, so don't subtract sector_offset here.
954          */
955 #ifdef  USE_SCG
956         readsecs(16 + toc_offset, &ipd, ISO_BLOCKS(sizeof (ipd)));
957 #else
958         lseek(fileno(infile), ((off_t)(16 + toc_offset)) <<11, SEEK_SET);
959         read(fileno(infile), &ipd, sizeof (ipd));
960 #endif
961         idr = (struct iso_directory_record *)ipd.root_directory_record;
962         if (do_pvd) {
963                 /*
964                  * High sierra:
965                  *
966                  *      DESC TYPE       == 1 (VD_SFS)   offset 8        len 1
967                  *      STR ID          == "CDROM"      offset 9        len 5
968                  *      STD_VER         == 1            offset 14       len 1
969                  */
970                 if ((((char *)&ipd)[8] == 1) &&
971                     (strncmp(&((char *)&ipd)[9], "CDROM", 5) == 0) &&
972                     (((char *)&ipd)[14] == 1)) {
973                         printf("CD-ROM is in High Sierra format\n");
974                         exit(0);
975                 }
976                 /*
977                  * ISO 9660:
978                  *
979                  *      DESC TYPE       == 1 (VD_PVD)   offset 0        len 1
980                  *      STR ID          == "CD001"      offset 1        len 5
981                  *      STD_VER         == 1            offset 6        len 1
982                  */
983                 if ((ipd.type[0] != ISO_VD_PRIMARY) ||
984                     (strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
985                     (ipd.version[0] != 1)) {
986                         printf("CD-ROM is NOT in ISO 9660 format\n");
987                         exit(1);
988                 }
989
990                 printf("CD-ROM is in ISO 9660 format\n");
991                 printf("System id: ");
992                 printchars(ipd.system_id, 32);
993                 putchar('\n');
994                 printf("Volume id: ");
995                 printchars(ipd.volume_id, 32);
996                 putchar('\n');
997
998                 printf("Volume set id: ");
999                 printchars(ipd.volume_set_id, 128);
1000                 putchar('\n');
1001                 printf("Publisher id: ");
1002                 printchars(ipd.publisher_id, 128);
1003                 putchar('\n');
1004                 printf("Data preparer id: ");
1005                 printchars(ipd.preparer_id, 128);
1006                 putchar('\n');
1007                 printf("Application id: ");
1008                 printchars(ipd.application_id, 128);
1009                 putchar('\n');
1010
1011                 printf("Copyright File id: ");
1012                 printchars(ipd.copyright_file_id, 37);
1013                 putchar('\n');
1014                 printf("Abstract File id: ");
1015                 printchars(ipd.abstract_file_id, 37);
1016                 putchar('\n');
1017                 printf("Bibliographic File id: ");
1018                 printchars(ipd.bibliographic_file_id, 37);
1019                 putchar('\n');
1020
1021                 printf("Volume set size is: %d\n", isonum_723(ipd.volume_set_size));
1022                 printf("Volume set sequence number is: %d\n", isonum_723(ipd.volume_sequence_number));
1023                 printf("Logical block size is: %d\n", isonum_723(ipd.logical_block_size));
1024                 printf("Volume size is: %d\n", isonum_733((unsigned char *)ipd.volume_space_size));
1025                 if (debug) {
1026                         int     dextent;
1027                         int     dlen;
1028
1029                         dextent = isonum_733((unsigned char *)idr->extent);
1030                         dlen = isonum_733((unsigned char *)idr->size);
1031                         printf("Root directory extent:  %d size: %d\n",
1032                                 dextent, dlen);
1033                         printf("Path table size is:     %d\n",
1034                                 isonum_733((unsigned char *)ipd.path_table_size));
1035                         printf("L Path table start:     %d\n",
1036                                 isonum_731(ipd.type_l_path_table));
1037                         printf("L Path opt table start: %d\n",
1038                                 isonum_731(ipd.opt_type_l_path_table));
1039                         printf("M Path table start:     %d\n",
1040                                 isonum_732(ipd.type_m_path_table));
1041                         printf("M Path opt table start: %d\n",
1042                                 isonum_732(ipd.opt_type_m_path_table));
1043                         printf("Creation Date:     %s\n",
1044                                 sdate(ipd.creation_date));
1045                         printf("Modification Date: %s\n",
1046                                 sdate(ipd.modification_date));
1047                         printf("Expiration Date:   %s\n",
1048                                 sdate(ipd.expiration_date));
1049                         printf("Effective Date:    %s\n",
1050                                 sdate(ipd.effective_date));
1051                         printf("File structure version: %d\n",
1052                                 ipd.file_structure_version[0]);
1053                 }
1054                 {
1055                         int     block = 16;
1056                         movebytes(&ipd, &jpd, sizeof (ipd));
1057                         while ((Uchar)jpd.type[0] != ISO_VD_END) {
1058
1059                                 if (debug && (Uchar) jpd.type[0] == ISO_VD_SUPPLEMENTARY)
1060                                         fprintf(stderr, "Joliet escape sequence 0: '%c' 1: '%c' 2: '%c' 3: '%c'\n",
1061                                                 jpd.escape_sequences[0],
1062                                                 jpd.escape_sequences[1],
1063                                                 jpd.escape_sequences[2],
1064                                                 jpd.escape_sequences[3]);
1065                                         /*
1066                                          * If Joliet UCS escape sequence found, we may be wrong
1067                                          */
1068                                         if (jpd.escape_sequences[0] == '%' &&
1069                                             jpd.escape_sequences[1] == '/' &&
1070                                             (jpd.escape_sequences[3] == '\0' ||
1071                                             jpd.escape_sequences[3] == ' ') &&
1072                                             (jpd.escape_sequences[2] == '@' ||
1073                                             jpd.escape_sequences[2] == 'C' ||
1074                                             jpd.escape_sequences[2] == 'E')) {
1075
1076                                                 if (jpd.version[0] == 1)
1077                                                         goto nextblock;
1078                                 }
1079                                 if (jpd.type[0] == 0) {
1080                                         movebytes(&jpd, &bpd, sizeof (bpd));
1081                                         if (strncmp(bpd.system_id, EL_TORITO_ID, sizeof (EL_TORITO_ID)) == 0) {
1082                                                 bootcat_offset = (Uchar)bpd.bootcat_ptr[0] +
1083                                                                 (Uchar)bpd.bootcat_ptr[1] * 256 +
1084                                                                 (Uchar)bpd.bootcat_ptr[2] * 65536 +
1085                                                                 (Uchar)bpd.bootcat_ptr[3] * 16777216;
1086                                                 found_eltorito = TRUE;
1087                                                 printf("El Torito VD version %d found, boot catalog is in sector %d\n",
1088                                                         bpd.version[0],
1089                                                         bootcat_offset);
1090                                         }
1091                                 }
1092                                 if (jpd.version[0] == 2) {
1093                                         printf("CD-ROM uses ISO 9660:1999 relaxed format\n");
1094                                         break;
1095                                 }
1096
1097                         nextblock:
1098                                 block++;
1099 #ifdef  USE_SCG
1100                                 readsecs(block + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd)));
1101 #else
1102                                 lseek(fileno(infile), ((off_t)(block + toc_offset)) <<11, SEEK_SET);
1103                                 read(fileno(infile), &jpd, sizeof (jpd));
1104 #endif
1105                         }
1106                 }
1107         }
1108         /*
1109          * ISO 9660:
1110          *
1111          *      DESC TYPE       == 1 (VD_PVD)   offset 0        len 1
1112          *      STR ID          == "CD001"      offset 1        len 5
1113          *      STD_VER         == 1            offset 6        len 1
1114          */
1115         if ((ipd.type[0] != ISO_VD_PRIMARY) ||
1116             (strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
1117             (ipd.version[0] != 1)) {
1118                 printf("CD-ROM is NOT in ISO 9660 format\n");
1119                 exit(1);
1120         }
1121
1122         if (use_joliet || do_pvd) {
1123                 int block = 16;
1124                 movebytes(&ipd, &jpd, sizeof (ipd));
1125                 while ((unsigned char) jpd.type[0] != ISO_VD_END) {
1126                         if (debug && (unsigned char) jpd.type[0] == ISO_VD_SUPPLEMENTARY)
1127                                 fprintf(stderr, "Joliet escape sequence 0: '%c' 1: '%c' 2: '%c' 3: '%c'\n",
1128                                         jpd.escape_sequences[0],
1129                                         jpd.escape_sequences[1],
1130                                         jpd.escape_sequences[2],
1131                                         jpd.escape_sequences[3]);
1132                         /*
1133                          * Find the UCS escape sequence.
1134                          */
1135                         if (jpd.escape_sequences[0] == '%' &&
1136                             jpd.escape_sequences[1] == '/' &&
1137                             (jpd.escape_sequences[3] == '\0' ||
1138                             jpd.escape_sequences[3] == ' ') &&
1139                             (jpd.escape_sequences[2] == '@' ||
1140                             jpd.escape_sequences[2] == 'C' ||
1141                             jpd.escape_sequences[2] == 'E')) {
1142                                 break;
1143                         }
1144
1145                         block++;
1146 #ifdef  USE_SCG
1147                         readsecs(block + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd)));
1148 #else
1149                         lseek(fileno(infile),
1150                                 ((off_t)(block + toc_offset)) <<11, SEEK_SET);
1151                         read(fileno(infile), &jpd, sizeof (jpd));
1152 #endif
1153                 }
1154
1155                 if (use_joliet && ((unsigned char) jpd.type[0] == ISO_VD_END)) {
1156 #ifdef  USE_LIBSCHILY
1157                         comerrno(EX_BAD, "Unable to find Joliet SVD\n");
1158 #else
1159                         fprintf(stderr, "Unable to find Joliet SVD\n");
1160                         exit(1);
1161 #endif
1162                 }
1163
1164                 switch (jpd.escape_sequences[2]) {
1165                 case '@':
1166                         ucs_level = 1;
1167                         break;
1168                 case 'C':
1169                         ucs_level = 2;
1170                         break;
1171                 case 'E':
1172                         ucs_level = 3;
1173                         break;
1174                 }
1175
1176                 if (ucs_level > 3) {
1177 #ifdef  USE_LIBSCHILY
1178                         comerrno(EX_BAD,
1179                                 "Don't know what ucs_level == %d means\n",
1180                                 ucs_level);
1181 #else
1182                         fprintf(stderr,
1183                                 "Don't know what ucs_level == %d means\n",
1184                                 ucs_level);
1185                         exit(1);
1186 #endif
1187                 }
1188                 if (jpd.escape_sequences[3] == ' ')
1189                         errmsgno(EX_BAD,
1190                         "Warning: Joliet escape sequence uses illegal space at offset 3\n");
1191         }
1192
1193         if (do_pvd) {
1194                 if (ucs_level > 0)
1195                         printf("Joliet with UCS level %d found\n", ucs_level);
1196                 else
1197                         printf("NO Joliet present\n");
1198
1199                 extent = isonum_733((unsigned char *)idr->extent);
1200
1201 #ifdef  USE_SCG
1202                 readsecs(extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer)));
1203 #else
1204                 lseek(fileno(infile),
1205                         ((off_t)(extent - sector_offset)) <<11, SEEK_SET);
1206                 read(fileno(infile), buffer, sizeof (buffer));
1207 #endif
1208                 idr = (struct iso_directory_record *) buffer;
1209                 if ((c = dump_rr(idr)) != 0) {
1210 /*                      printf("RR %X %d\n", c, c);*/
1211                         if (c & 1024) {
1212                                 printf(
1213                                 "Rock Ridge signatures version %d found\n",
1214                                 su_version);
1215                         } else {
1216                                 printf(
1217                                 "Bad Rock Ridge signatures found (SU record missing)\n");
1218                         }
1219                         /*
1220                          * This is currently a no op!
1221                          * We need to check the first plain file instead of
1222                          * the '.' entry in the root directory.
1223                          */
1224                         if (c & 2048) {
1225                                 printf("Apple signatures version %d found\n",
1226                                                                 aa_version);
1227                         }
1228                 } else {
1229                         printf("NO Rock Ridge present\n");
1230                 }
1231                 if (found_eltorito)
1232                         printf_bootinfo(infile, bootcat_offset);
1233                 exit(0);
1234         }
1235
1236         if (use_joliet)
1237                 idr = (struct iso_directory_record *)jpd.root_directory_record;
1238
1239         if (do_pathtab) {
1240                 if (use_joliet) {
1241                         dump_pathtab(isonum_731(jpd.type_l_path_table),
1242                         isonum_733((unsigned char *)jpd.path_table_size));
1243                 } else {
1244                         dump_pathtab(isonum_731(ipd.type_l_path_table),
1245                         isonum_733((unsigned char *)ipd.path_table_size));
1246                 }
1247         }
1248
1249         parse_dir("/", isonum_733((unsigned char *)idr->extent),
1250                                 isonum_733((unsigned char *)idr->size));
1251         td = todo_idr;
1252         while (td) {
1253                 parse_dir(td->name, td->extent, td->length);
1254                 td = td->next;
1255         }
1256
1257         if (infile != NULL)
1258                 fclose(infile);
1259         return (0);
1260 }
1261
1262 #include <intcvt.h>
1263
1264 static void
1265 printf_bootinfo(FILE *f, int bootcat_offset)
1266 {
1267         struct eltorito_validation_entry        *evp;
1268         struct eltorito_defaultboot_entry       *ebe;
1269
1270 #ifdef  USE_SCG
1271         readsecs(bootcat_offset, buffer, ISO_BLOCKS(sizeof (buffer)));
1272 #else
1273         lseek(fileno(f), ((off_t)bootcat_offset) <<11, SEEK_SET);
1274         read(fileno(f), buffer, sizeof (buffer));
1275 #endif
1276
1277         evp = (struct eltorito_validation_entry *)buffer;
1278         ebe = (struct eltorito_defaultboot_entry *)&buffer[32];
1279
1280         printf("Eltorito validation header:\n");
1281         printf("    Hid %d\n", (Uchar)evp->headerid[0]);
1282         printf("    Arch %d (%s)\n", (Uchar)evp->arch[0], arch_name((Uchar)evp->arch[0]));
1283         printf("    ID '%.23s'\n", evp->id);
1284         printf("    Key %X %X\n", (Uchar)evp->key1[0], (Uchar)evp->key2[0]);
1285
1286         printf("    Eltorito defaultboot header:\n");
1287         printf("        Bootid %X (%s)\n", (Uchar)ebe->boot_id[0], boot_name((Uchar)ebe->boot_id[0]));
1288         printf("        Boot media %X (%s)\n", (Uchar)ebe->boot_media[0], bootmedia_name((Uchar)ebe->boot_media[0]));
1289         printf("        Load segment %X\n", la_to_2_byte(ebe->loadseg));
1290         printf("        Sys type %X\n", (Uchar)ebe->sys_type[0]);
1291         printf("        Nsect %X\n", la_to_2_byte(ebe->nsect));
1292         printf("        Bootoff %lX %ld\n", la_to_4_byte(ebe->bootoff), la_to_4_byte(ebe->bootoff));
1293
1294 }
1295
1296 static char *
1297 arch_name(int val)
1298 {
1299         switch (val) {
1300
1301         case EL_TORITO_ARCH_x86:
1302                 return ("x86");
1303         case EL_TORITO_ARCH_PPC:
1304                 return ("PPC");
1305         case EL_TORITO_ARCH_MAC:
1306                 return ("MAC");
1307         default:
1308                 return ("Unknown Arch");
1309         }
1310 }
1311
1312 static char *
1313 boot_name(int val)
1314 {
1315         switch (val) {
1316
1317         case EL_TORITO_BOOTABLE:
1318                 return ("bootable");
1319         case EL_TORITO_NOT_BOOTABLE:
1320                 return ("not bootable");
1321         default:
1322                 return ("Illegal");
1323         }
1324 }
1325
1326 static char *
1327 bootmedia_name(int val)
1328 {
1329         switch (val) {
1330
1331         case EL_TORITO_MEDIA_NOEMUL:
1332                 return ("No Emulation Boot");
1333         case EL_TORITO_MEDIA_12FLOP:
1334                 return ("1200 Floppy");
1335         case EL_TORITO_MEDIA_144FLOP:
1336                 return ("1.44MB Floppy");
1337         case EL_TORITO_MEDIA_288FLOP:
1338                 return ("2.88MB Floppy");
1339         case EL_TORITO_MEDIA_HD:
1340                 return ("Hard Disk Emulation");
1341         default:
1342                 return ("Illegal Bootmedia");
1343         }
1344 }