Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / genisoimage / diag / isodump.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 /* @(#)isodump.c        1.27 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 #include <mconfig.h>
38 #include <stdxlib.h>
39 #include <unixstd.h>
40 #include <strdefs.h>
41 #include <utypes.h>
42
43 #include <stdio.h>
44 #include <standard.h>
45 #include <ttydefs.h>
46 #include <signal.h>
47 #include <schily.h>
48
49 #include "../scsi.h"
50 #include "../../wodim/defaults.h"
51
52 /*
53  * XXX JS: Some structures have odd lengths!
54  * Some compilers (e.g. on Sun3/mc68020) padd the structures to even length.
55  * For this reason, we cannot use sizeof (struct iso_path_table) or
56  * sizeof (struct iso_directory_record) to compute on disk sizes.
57  * Instead, we use offsetof(..., name) and add the name size.
58  * See iso9660.h
59  */
60 #ifndef offsetof
61 #define offsetof(TYPE, MEMBER)  ((size_t) &((TYPE *)0)->MEMBER)
62 #endif
63
64 /*
65  * Note: always use these macros to avoid problems.
66  *
67  * ISO_ROUND_UP(X)      may cause an integer overflow and thus give
68  *                      incorrect results. So avoid it if possible.
69  *
70  * ISO_BLOCKS(X)        is overflow safe. Prefer this when ever it is possible.
71  */
72 #define SECTOR_SIZE     (2048)
73 #define ISO_ROUND_UP(X) (((X) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))
74 #define ISO_BLOCKS(X)   (((X) / SECTOR_SIZE) + (((X)%SECTOR_SIZE)?1:0))
75
76 #define infile  in_image
77 FILE    *infile = NULL;
78 off_t   file_addr;
79 unsigned char buffer[2048];
80 unsigned char search[64];
81 int blocksize;
82
83 #define PAGE    sizeof (buffer)
84
85 #define ISODCL(from, to)        (to - from + 1)
86
87 struct iso_primary_descriptor {
88         unsigned char type                      [ISODCL(1,   1)]; /* 711 */
89         unsigned char id                        [ISODCL(2,   6)];
90         unsigned char version                   [ISODCL(7,   7)]; /* 711 */
91         unsigned char unused1                   [ISODCL(8,   8)];
92         unsigned char system_id                 [ISODCL(9,   40)]; /* aunsigned chars */
93         unsigned char volume_id                 [ISODCL(41,  72)]; /* dunsigned chars */
94         unsigned char unused2                   [ISODCL(73,  80)];
95         unsigned char volume_space_size         [ISODCL(81,  88)]; /* 733 */
96         unsigned char unused3                   [ISODCL(89,  120)];
97         unsigned char volume_set_size           [ISODCL(121, 124)]; /* 723 */
98         unsigned char volume_sequence_number    [ISODCL(125, 128)]; /* 723 */
99         unsigned char logical_block_size        [ISODCL(129, 132)]; /* 723 */
100         unsigned char path_table_size           [ISODCL(133, 140)]; /* 733 */
101         unsigned char type_l_path_table         [ISODCL(141, 144)]; /* 731 */
102         unsigned char opt_type_l_path_table     [ISODCL(145, 148)]; /* 731 */
103         unsigned char type_m_path_table         [ISODCL(149, 152)]; /* 732 */
104         unsigned char opt_type_m_path_table     [ISODCL(153, 156)]; /* 732 */
105         unsigned char root_directory_record     [ISODCL(157, 190)]; /* 9.1 */
106         unsigned char volume_set_id             [ISODCL(191, 318)]; /* dunsigned chars */
107         unsigned char publisher_id              [ISODCL(319, 446)]; /* achars */
108         unsigned char preparer_id               [ISODCL(447, 574)]; /* achars */
109         unsigned char application_id            [ISODCL(575, 702)]; /* achars */
110         unsigned char copyright_file_id         [ISODCL(703, 739)]; /* 7.5 dchars */
111         unsigned char abstract_file_id          [ISODCL(740, 776)]; /* 7.5 dchars */
112         unsigned char bibliographic_file_id     [ISODCL(777, 813)]; /* 7.5 dchars */
113         unsigned char creation_date             [ISODCL(814, 830)]; /* 8.4.26.1 */
114         unsigned char modification_date         [ISODCL(831, 847)]; /* 8.4.26.1 */
115         unsigned char expiration_date           [ISODCL(848, 864)]; /* 8.4.26.1 */
116         unsigned char effective_date            [ISODCL(865, 881)]; /* 8.4.26.1 */
117         unsigned char file_structure_version    [ISODCL(882, 882)]; /* 711 */
118         unsigned char unused4                   [ISODCL(883, 883)];
119         unsigned char application_data          [ISODCL(884, 1395)];
120         unsigned char unused5                   [ISODCL(1396, 2048)];
121 };
122
123 struct iso_directory_record {
124         unsigned char length                    [ISODCL(1, 1)]; /* 711 */
125         unsigned char ext_attr_length           [ISODCL(2, 2)]; /* 711 */
126         unsigned char extent                    [ISODCL(3, 10)]; /* 733 */
127         unsigned char size                      [ISODCL(11, 18)]; /* 733 */
128         unsigned char date                      [ISODCL(19, 25)]; /* 7 by 711 */
129         unsigned char flags                     [ISODCL(26, 26)];
130         unsigned char file_unit_size            [ISODCL(27, 27)]; /* 711 */
131         unsigned char interleave                [ISODCL(28, 28)]; /* 711 */
132         unsigned char volume_sequence_number    [ISODCL(29, 32)]; /* 723 */
133         unsigned char name_len                  [ISODCL(33, 33)]; /* 711 */
134         unsigned char name                      [1];
135 };
136
137 static int      isonum_731(char * p);
138 static int      isonum_72(char * p);
139 static int      isonum_723(char * p);
140 static int      isonum_733(unsigned char * p);
141 static void     reset_tty(void);
142 static void     set_tty(void);
143 static void     onsusp(int signo);
144 static void     crsr2(int row, int col);
145 static int      parse_rr(unsigned char * pnt, int len, int cont_flag);
146 static void     dump_rr(struct iso_directory_record * idr);
147 static void     showblock(int flag);
148 static int      getbyte(void);
149 static void     usage(int excode);
150
151 static int
152 isonum_731(char *p)
153 {
154         return ((p[0] & 0xff)
155                 | ((p[1] & 0xff) << 8)
156                 | ((p[2] & 0xff) << 16)
157                 | ((p[3] & 0xff) << 24));
158 }
159
160 static int
161 isonum_721(char *p)
162 {
163         return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
164 }
165
166 static int
167 isonum_723(char *p)
168 {
169 #if 0
170         if (p[0] != p[3] || p[1] != p[2]) {
171 #ifdef  USE_LIBSCHILY
172                 comerrno(EX_BAD, "invalid format 7.2.3 number\n");
173 #else
174                 fprintf(stderr, "invalid format 7.2.3 number\n");
175                 exit(1);
176 #endif
177         }
178 #endif
179         return (isonum_721(p));
180 }
181
182
183 static int
184 isonum_733(unsigned char *p)
185 {
186         return (isonum_731((char *)p));
187 }
188
189 #ifdef  USE_V7_TTY
190 static  struct sgttyb   savetty;
191 static  struct sgttyb   newtty;
192 #else
193 static  struct termios savetty;
194 static  struct termios newtty;
195 #endif
196
197 static void
198 reset_tty()
199 {
200 #ifdef USE_V7_TTY
201         if (ioctl(STDIN_FILENO, TIOCSETN, &savetty) == -1) {
202 #else
203 #ifdef TCSANOW
204         if (tcsetattr(STDIN_FILENO, TCSANOW, &savetty) == -1)  {
205 #else
206         if (ioctl(STDIN_FILENO, TCSETAF, &savetty) == -1) {
207 #endif
208 #endif
209 #ifdef  USE_LIBSCHILY
210                 comerr("Cannot put tty into normal mode\n");
211 #else
212                 printf("Cannot put tty into normal mode\n");
213                 exit(1);
214 #endif
215         }
216 }
217
218 static void
219 set_tty()
220 {
221 #ifdef USE_V7_TTY
222         if (ioctl(STDIN_FILENO, TIOCSETN, &newtty) == -1) {
223 #else
224 #ifdef TCSANOW
225         if (tcsetattr(STDIN_FILENO, TCSANOW, &newtty) == -1) {
226 #else
227         if (ioctl(STDIN_FILENO, TCSETAF, &newtty) == -1) {
228 #endif
229 #endif
230 #ifdef  USE_LIBSCHILY
231                 comerr("Cannot put tty into raw mode\n");
232 #else
233                 printf("Cannot put tty into raw mode\n");
234                 exit(1);
235 #endif
236         }
237 }
238
239 /* Come here when we get a suspend signal from the terminal */
240
241 static void
242 onsusp(int signo)
243 {
244 #ifdef  SIGTTOU
245         /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
246         signal(SIGTTOU, SIG_IGN);
247 #endif
248         reset_tty();
249         fflush(stdout);
250 #ifdef  SIGTTOU
251         signal(SIGTTOU, SIG_DFL);
252         /* Send the TSTP signal to suspend our process group */
253         signal(SIGTSTP, SIG_DFL);
254 /*      sigsetmask(0);*/
255         kill(0, SIGTSTP);
256         /* Pause for station break */
257
258         /* We're back */
259         signal(SIGTSTP, onsusp);
260 #endif
261         set_tty();
262 }
263
264
265
266 static void
267 crsr2(int row, int col)
268 {
269         printf("\033[%d;%dH", row, col);
270 }
271
272 static int
273 parse_rr(unsigned char *pnt, int len, int cont_flag)
274 {
275         int             slen;
276         int             ncount;
277         int             extent;
278         off_t           cont_extent;
279         int             cont_offset;
280         int             cont_size;
281         int             flag1;
282         int             flag2;
283         unsigned char   *pnts;
284         char            symlinkname[1024];
285         char            name[1024];
286         int             goof;
287
288 /*      printf(" RRlen=%d ", len); */
289
290         symlinkname[0] = 0;
291
292         cont_extent = (off_t)0;
293         cont_offset = cont_size = 0;
294
295         ncount = 0;
296         flag1 = flag2 = 0;
297         while (len >= 4) {
298                 if (ncount)
299                         printf(",");
300                 else
301                         printf("[");
302                 printf("%c%c", pnt[0], pnt[1]);
303                 if (pnt[3] != 1 && pnt[3] != 2) {
304                         printf("**BAD RRVERSION (%d) for %c%c\n", pnt[3], pnt[0], pnt[1]);
305                         return (0);     /* JS ??? Is this right ??? */
306                 } else if (pnt[0] == 'R' && pnt[1] == 'R') {
307                         printf("=%d", pnt[3]);
308                 }
309                 ncount++;
310                 if (pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
311                 if (strncmp((char *)pnt, "PX", 2) == 0) flag2 |= 1;
312                 if (strncmp((char *)pnt, "PN", 2) == 0) flag2 |= 2;
313                 if (strncmp((char *)pnt, "SL", 2) == 0) flag2 |= 4;
314                 if (strncmp((char *)pnt, "NM", 2) == 0) {
315                         slen = pnt[2] - 5;
316                         pnts = pnt+5;
317                         if ((pnt[4] & 6) != 0) {
318                                 printf("*");
319                         }
320                         memset(name, 0, sizeof (name));
321                         memcpy(name, pnts, slen);
322                         printf("=%s", name);
323                         flag2 |= 8;
324                 }
325                 if (strncmp((char *)pnt, "CL", 2) == 0) flag2 |= 16;
326                 if (strncmp((char *)pnt, "PL", 2) == 0) flag2 |= 32;
327                 if (strncmp((char *)pnt, "RE", 2) == 0) flag2 |= 64;
328                 if (strncmp((char *)pnt, "TF", 2) == 0) flag2 |= 128;
329
330                 if (strncmp((char *)pnt, "PX", 2) == 0) {
331                         extent = isonum_733(pnt+12);
332                         printf("=%x", extent);
333                 }
334
335                 if (strncmp((char *)pnt, "CE", 2) == 0) {
336                         cont_extent = (off_t)isonum_733(pnt+4);
337                         cont_offset = isonum_733(pnt+12);
338                         cont_size = isonum_733(pnt+20);
339                         printf("=[%x,%x,%d]", (int)cont_extent, cont_offset,
340                                                                 cont_size);
341                 }
342
343                 if (strncmp((char *)pnt, "PL", 2) == 0 || strncmp((char *)pnt, "CL", 2) == 0) {
344                         extent = isonum_733(pnt+4);
345                         printf("=%x", extent);
346                 }
347
348                 if (strncmp((char *)pnt, "SL", 2) == 0) {
349                         int     cflag;
350
351                         cflag = pnt[4];
352                         pnts = pnt+5;
353                         slen = pnt[2] - 5;
354                         while (slen >= 1) {
355                                 switch (pnts[0] & 0xfe) {
356                                 case 0:
357                                         strncat(symlinkname, (char *)(pnts+2), pnts[1]);
358                                         break;
359                                 case 2:
360                                         strcat(symlinkname, ".");
361                                         break;
362                                 case 4:
363                                         strcat(symlinkname, "..");
364                                         break;
365                                 case 8:
366                                         if ((pnts[0] & 1) == 0)
367                                                 strcat(symlinkname, "/");
368                                         break;
369                                 case 16:
370                                         strcat(symlinkname, "/mnt");
371                                         printf("Warning - mount point requested");
372                                         break;
373                                 case 32:
374                                         strcat(symlinkname, "kafka");
375                                         printf("Warning - host_name requested");
376                                         break;
377                                 default:
378                                         printf("Reserved bit setting in symlink");
379                                         goof++;
380                                         break;
381                                 }
382                                 if ((pnts[0] & 0xfe) && pnts[1] != 0) {
383                                         printf("Incorrect length in symlink component");
384                                 }
385                                 if ((pnts[0] & 1) == 0)
386                                         strcat(symlinkname, "/");
387
388                                 slen -= (pnts[1] + 2);
389                                 pnts += (pnts[1] + 2);
390                         }
391                         if (cflag)
392                                 strcat(symlinkname, "+");
393                         printf("=%s", symlinkname);
394                         symlinkname[0] = 0;
395                 }
396
397                 len -= pnt[2];
398                 pnt += pnt[2];
399                 if (len <= 3 && cont_extent) {
400                         unsigned char sector[2048];
401
402 #ifdef  USE_SCG
403                         readsecs(cont_extent * blocksize / 2048, sector, ISO_BLOCKS(sizeof (sector)));
404 #else
405                         lseek(fileno(infile), cont_extent * blocksize, SEEK_SET);
406                         read(fileno(infile), sector, sizeof (sector));
407 #endif
408                         flag2 |= parse_rr(&sector[cont_offset], cont_size, 1);
409                 }
410         }
411         if (ncount)
412                 printf("]");
413         if (!cont_flag && flag1 != flag2) {
414                 printf("Flag %x != %x", flag1, flag2);
415                 goof++;
416         }
417         return (flag2);
418 }
419
420 static void
421 dump_rr(struct iso_directory_record *idr)
422 {
423         int             len;
424         unsigned char   *pnt;
425
426         len = idr->length[0] & 0xff;
427         len -= offsetof(struct iso_directory_record, name[0]);
428         len -= idr->name_len[0];
429         pnt = (unsigned char *) idr;
430         pnt += offsetof(struct iso_directory_record, name[0]);
431         pnt += idr->name_len[0];
432         if ((idr->name_len[0] & 1) == 0) {
433                 pnt++;
434                 len--;
435         }
436         parse_rr(pnt, len, 0);
437 }
438
439
440 static void
441 showblock(int flag)
442 {
443         int     i;
444         int     j;
445         int     line;
446         struct iso_directory_record     *idr;
447
448 #ifdef  USE_SCG
449         readsecs(file_addr / 2048, buffer, ISO_BLOCKS(sizeof (buffer)));
450 #else
451         lseek(fileno(infile), file_addr, SEEK_SET);
452         read(fileno(infile), buffer, sizeof (buffer));
453 #endif
454         for (i = 0; i < 60; i++)
455                 printf("\n");
456         fflush(stdout);
457         i = line = 0;
458         if (flag) {
459                 while (1 == 1) {
460                         crsr2(line+3, 1);
461                         idr = (struct iso_directory_record *) &buffer[i];
462                         if (idr->length[0] == 0)
463                                 break;
464                         printf("%3d ", idr->length[0]);
465                         printf("[%2d] ", idr->volume_sequence_number[0]);
466                         printf("%5x ", isonum_733(idr->extent));
467                         printf("%8d ", isonum_733(idr->size));
468                         printf("%02x/", idr->flags[0]);
469                         printf((idr->flags[0] & 2) ? "*" : " ");
470                         if (idr->name_len[0] == 1 && idr->name[0] == 0)
471                                 printf(".             ");
472                         else if (idr->name_len[0] == 1 && idr->name[0] == 1)
473                                 printf("..            ");
474                         else {
475                                 for (j = 0; j < (int)idr->name_len[0]; j++) printf("%c", idr->name[j]);
476                                 for (j = 0; j < (14 - (int)idr->name_len[0]); j++) printf(" ");
477                         }
478                         dump_rr(idr);
479                         printf("\n");
480                         i += buffer[i];
481                         if (i > 2048 - offsetof(struct iso_directory_record, name[0]))
482                                 break;
483                         line++;
484                 }
485         }
486         printf("\n");
487         if (sizeof (file_addr) > sizeof (long)) {
488                 printf(" Zone, zone offset: %14llx %12.12llx  ",
489                         (Llong)file_addr / blocksize,
490                         (Llong)file_addr & (Llong)(blocksize - 1));
491         } else {
492                 printf(" Zone, zone offset: %6lx %4.4lx  ",
493                         (long) (file_addr / blocksize),
494                         (long) file_addr & (blocksize - 1));
495         }
496         fflush(stdout);
497 }
498
499 static int
500 getbyte()
501 {
502         char    c1;
503
504         c1 = buffer[file_addr & (blocksize-1)];
505         file_addr++;
506         if ((file_addr & (blocksize-1)) == 0)
507                 showblock(0);
508         return (c1);
509 }
510
511 static void
512 usage(int excode)
513 {
514         errmsgno(EX_BAD, "Usage: %s [options] image\n",
515                                                 get_progname());
516
517         fprintf(stderr, "Options:\n");
518         fprintf(stderr, "\t-help, -h    Print this help\n");
519         fprintf(stderr, "\t-version     Print version info and exit\n");
520         fprintf(stderr, "\t-i filename  Filename to read ISO-9660 image from\n");
521         fprintf(stderr, "\tdev=target   SCSI target to use as CD/DVD-Recorder\n");
522         fprintf(stderr, "\nIf neither -i nor dev= are speficied, <image> is needed.\n");
523         exit(excode);
524 }
525
526 int
527 main(int argc, char *argv[])
528 {
529         int     cac;
530         char    * const *cav;
531         char    *opts = "help,h,version,i*,dev*";
532         BOOL    help = FALSE;
533         BOOL    prvers = FALSE;
534         char    *filename = NULL;
535         char    *devname = NULL;
536         char    c;
537         int     i;
538         struct iso_primary_descriptor   ipd;
539         struct iso_directory_record     *idr;
540
541         save_args(argc, argv);
542
543         cac = argc - 1;
544         cav = argv + 1;
545         if (getallargs(&cac, &cav, opts, &help, &help, &prvers,
546                         &filename, &devname) < 0) {
547                 errmsgno(EX_BAD, "Bad Option: '%s'\n", cav[0]);
548                 usage(EX_BAD);
549         }
550         if (help)
551                 usage(0);
552         if (prvers) {
553                 printf("isodump %s (%s)\n", CDRKIT_VERSION, HOST_SYSTEM);
554                 exit(0);
555         }
556         cac = argc - 1;
557         cav = argv + 1;
558         if (filename == NULL && devname == NULL) {
559                 if (getfiles(&cac, &cav, opts) != 0) {
560                         filename = cav[0];
561                         cac--, cav++;
562                 }
563         }
564         if (getfiles(&cac, &cav, opts) != 0) {
565                 errmsgno(EX_BAD, "Bad Argument: '%s'\n", cav[0]);
566                 usage(EX_BAD);
567         }
568         if (filename != NULL && devname != NULL) {
569                 errmsgno(EX_BAD, "Only one of -i or dev= allowed\n");
570                 usage(EX_BAD);
571         }
572 #ifdef  USE_SCG
573         if (filename == NULL && devname == NULL)
574                 cdr_defaults(&devname, NULL, NULL, NULL);
575 #endif
576         if (filename == NULL && devname == NULL) {
577 #ifdef  USE_LIBSCHILY
578                 errmsgno(EX_BAD, "ISO-9660 image not specified\n");
579 #else
580                 fprintf(stderr, "ISO-9660 image not specified\n");
581 #endif
582                 usage(EX_BAD);
583         }
584
585         if (filename != NULL)
586                 infile = fopen(filename, "rb");
587         else
588                 filename = devname;
589
590         if (infile != NULL) {
591                 /* EMPTY */;
592 #ifdef  USE_SCG
593         } else if (scsidev_open(filename) < 0) {
594 #else
595         } else {
596 #endif
597 #ifdef  USE_LIBSCHILY
598                 comerr("Cannot open '%s'\n", filename);
599 #else
600                 fprintf(stderr, "Cannot open '%s'\n", filename);
601                 exit(1);
602 #endif
603         }
604
605         file_addr = (off_t) (16 << 11);
606 #ifdef  USE_SCG
607         readsecs(file_addr / 2048, &ipd, ISO_BLOCKS(sizeof (ipd)));
608 #else
609         lseek(fileno(infile), file_addr, SEEK_SET);
610         read(fileno(infile), &ipd, sizeof (ipd));
611 #endif
612         idr = (struct iso_directory_record *)ipd.root_directory_record;
613
614         blocksize = isonum_723((char *)ipd.logical_block_size);
615         if (blocksize != 512 && blocksize != 1024 && blocksize != 2048) {
616                 blocksize = 2048;
617         }
618
619         file_addr = (off_t)isonum_733(idr->extent);
620         file_addr = file_addr * blocksize;
621
622 /* Now setup the keyboard for single character input. */
623 #ifdef USE_V7_TTY
624         if (ioctl(STDIN_FILENO, TIOCGETP, &savetty) == -1) {
625 #else
626 #ifdef TCSANOW
627         if (tcgetattr(STDIN_FILENO, &savetty) == -1) {
628 #else
629         if (ioctl(STDIN_FILENO, TCGETA, &savetty) == -1) {
630 #endif
631 #endif
632 #ifdef  USE_LIBSCHILY
633                 comerr("Stdin must be a tty\n");
634 #else
635                 printf("Stdin must be a tty\n");
636                 exit(1);
637 #endif
638         }
639         newtty = savetty;
640 #ifdef USE_V7_TTY
641         newtty.sg_flags  &= ~(ECHO|CRMOD);
642         newtty.sg_flags  |= CBREAK;
643 #else
644         newtty.c_lflag   &= ~ICANON;
645         newtty.c_lflag   &= ~ECHO;
646         newtty.c_cc[VMIN] = 1;
647 #endif
648         set_tty();
649 #ifdef  SIGTSTP
650         signal(SIGTSTP, onsusp);
651 #endif
652         on_comerr((void(*)(int, void *))reset_tty, NULL);
653
654         do {
655                 if (file_addr < 0)
656                         file_addr = (off_t)0;
657                 showblock(1);
658                 read(STDIN_FILENO, &c, 1); /* FIXME: check return value */
659                 if (c == 'a')
660                         file_addr -= blocksize;
661                 if (c == 'b')
662                         file_addr += blocksize;
663                 if (c == 'g') {
664                         crsr2(20, 1);
665                         printf("Enter new starting block (in hex):");
666                         if (sizeof (file_addr) > sizeof (long)) {
667                                 Llong   ll;
668                                 scanf("%llx", &ll); /* FIXME: check return value */
669                                 file_addr = (off_t)ll;
670                         } else {
671                                 long    l;
672                                 scanf("%lx", &l); /* FIXME: check return value */
673                                 file_addr = (off_t)l;
674                         }
675                         file_addr = file_addr * blocksize;
676                         crsr2(20, 1);
677                         printf("                                     ");
678                 }
679                 if (c == 'f') {
680                         crsr2(20, 1);
681                         printf("Enter new search string:");
682                         fgets((char *)search, sizeof (search), stdin); /* FIXME: check return value */
683                         while (search[strlen((char *)search)-1] == '\n')
684                                 search[strlen((char *)search)-1] = 0;
685                         crsr2(20, 1);
686                         printf("                                     ");
687                 }
688                 if (c == '+') {
689                         while (1 == 1) {
690                                 int     slen;
691
692                                 while (1 == 1) {
693                                         c = getbyte();
694                                         if (c == search[0])
695                                                 break;
696                                 }
697                                 slen = (int)strlen((char *)search);
698                                 for (i = 1; i < slen; i++) {
699                                         if (search[i] != getbyte())
700                                                 break;
701                                 }
702                                 if (i == slen)
703                                         break;
704                         }
705                         file_addr &= ~(blocksize-1);
706                         showblock(1);
707                 }
708                 if (c == 'q')
709                         break;
710         } while (1 == 1);
711         reset_tty();
712         if (infile != NULL)
713                 fclose(infile);
714         return (0);
715 }