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