/*)BUILD $(TKBOPTIONS) = { TASK = ...SOD } */ /* * od [-5abhrwx] [-f bn] [-l bn] file * * od File dumper * * This programme is a replacement for DMP. It does most things that are * done by DMP, and does them in a more reasonable way; in particular, you * can dump in more than one format at once, and you can get a nice header * dump, with all the newest ODS-1 stuff in it. It'll dump anything. * * Its options are: * -a Dump ASCII characters * -b Dump octal bytes * -f # Set first block, default is 0 * -h Dump the file header * -l # Set last block, default is EOF * -r Dump by record * -w Dump octal words * -x Dump hexadecimal bytes * -5 Dump radix 50 words. * * If no dump selection options are present, od defaults to -w. * * od only runs on the RSX library. * * Edited by Bob Denny. Bug fix (trapped), slight modification of * "header" line, fix so 1 byte records will dump in "-w" mode, * make VBN's long to support large files. * * Further edits by Bob Denny to add the full filespec to the * block/record heading, add "-h" switch for dumping the file * header, including multi-header files, with most of the (secret) * attributes, etc. * * Do all block image dumps using QIO's rather than fget(), as the * latter fails on "system" files such as INDEXF.SYS which have * nothing at all in the H.UFAT area of the header. It runs faster * this way too. Now frec() is used only on recordwise dumps. * * *************** * ** N O T E ** * *************** * * This program requires the RSX-11M/M+ executive * extensions library (CX.OLB) and the F11.H and QIOFUN.H * header files in LB:[1,1]. This stuff is in [5,7] of * the DECUS C kit. * * P.S. I don't apologise for the lack of comments (!) */ /***** UNDEFINE THIS FOR SMALLER PROGRAM WITH NO HEADER DUMP *****/ #define hdump #include #include /* I/O function codes */ #include /* I/O return codes */ #include /* File header structure definition */ #define IS_SUC 1 #define HUGE 04000000l /* Max blox on ODS-1 */ #define BSIZ 512 /* Block size */ int aflag = 0; /* Initialize these */ int bflag = 0; int fflag = 0; int hflag = 0; int rflag = 0; int wflag = 0; int xflag = 0; char *fn; /* Command line filename */ FILE *fp; /* IOV pointer */ char fspec[40]; /* Full filespec */ int fl; /* LUN of file */ int efl; /* LUN used for extension file */ int efn; /* Extension file number */ long fbn = 0l; /* Start VBN/Record */ long lbn = HUGE; /* Stop VBN/Record */ int max_size; char buf[BSIZ]; /* Gets header, blox, records */ char prot[20]; char prch[] = "RWED"; extern long ftell(); /* * Files-11 QIO stuff for reading file header and blocks */ int ratctl[3] = {0366, buf, 0}; /* Read att's control list */ int ratpar[6] = {0, ratctl, 0, 0, 0, 0}; /* IO.RAT parameters */ int blkmode = 0; /* 1 = block image dump w/QIO's */ struct pb { /* Makes handling long VBN easier */ char *bf; int size; int xxxx; long vbn; int yyyy; } rvbpar = {buf, BSIZ, 0, 0l, 0 }; int iosb[2]; main(argc, argv) char *argv[]; { /*register*/ int i; /*register*/ struct header *hdr; /* File header pointer */ /*register*/ char *p; int k; char *q; char c; long j; char *bp; struct ufat *ufp; fn = NULL; hdr = buf; /* buf used for header too */ for(i=1; i= argc) usage(); fbn = atol(argv[i]); break; case 'l': case 'L': if(++i >= argc) usage(); lbn = atol(argv[i]); break; default: usage(); } } else if(fn != NULL) usage(); else fn = p; } if(fn == NULL) usage(); if(lbn < fbn) usage(); if(!aflag && !bflag && !fflag && !hflag && !wflag && !xflag) ++wflag; /* * The following is an RSX-specific hack to control the format * in which the file is dumped. In particular, if the file is record * oriented, but the user did not set the "-r" switch, the attributes * in the FDB are fudged to make the FCS routines think it is an R.FIX * file with R.SIZE = 512. and no carriage control attributes. This * makes it default to dump a record file in block format, so you * can see all the RCW's etc. * * First, open the file in "u" mode to enable "user" record buffering. * Get the full filespec and LUN. */ if((fp=fopen(fn, "ru")) == NULL) cant(fn); iovtoa(fp, fspec); /* Get full filespec */ fl = flun(fp); /* Get LUN for later QIO's */ /* * Now, if it's not a "record oriented device" (CR, MT etc.), and * the "-r" switch wasn't set, dump in block image. */ max_size = fp->io_rbsz; bp = "** Record"; if(!rflag && !frec(fp)) { bp = "** Block"; /* Banner */ blkmode++; /* Mode = block image */ } /* * Read the file header. Point ufp to the user att's. */ qiow(IO_RAT,fl,15,0,0,ratpar); /* Read file header */ ufp = &(hdr->h_ufat); #ifdef hdump /* * If the "-h" switch set, dump the file header prettily * (this takes a ton of ugly code) */ efn = 0; /* Start with primary file */ hdrdump: /* Branch back for multi-header files */ if(hflag && !frec(fp)) /* Record devices have no header */ { printf("\n\n** DUMP OF %s\n", fspec); if(efn == 0) printf("** Primary File Header:"); else printf("** Extension File %d Header:", efn); printf("\n\nHeader area:\n\n"); printf("H.IDOF %03o H.MPOF %03o\n", hdr->h_idof, hdr->h_mpof); printf("H.FNUM,H.FSEQ,H.FLEV = (%06o,%06o,%06o)\n", hdr->h_fnum, hdr->h_fseq, hdr->h_flev); printf("H.PROJ %03o H.PROG %03o\n", hdr->h_proj, hdr->h_prog); p = prot; q = prch; k = hdr->h_fpro; for(i=0; i<16; i++) /* Check this out */ { if(*q == '\0') { q = prch; *p++ = ','; } if((k & 1) == 0) *p++ = *q++; else q++; k >>= 1; } *p = '\0'; printf("H.FPRO %06o = [%s]\n", hdr->h_fpro, prot); i = hdr->h_ucha&0377; printf("H.UCHA %03o = ", i); if(i & UC_DLK) printf("UC.DLK = Deaccess locked "); if(i & UC_CON) printf("UC.CON = Contiguous "); if(i & UC_NID) printf("UC.NID = No incr. dump "); if(i & UC_WBC) printf("UC.WBC = Write-back cache "); if(i & UC_RCK) printf("UC.RCK = Read check "); if(i & UC_WCK) printf("UC.WCK = Write check "); if(i & UC_CNB) printf("UC.CNB = Contig. best effort "); printf("\n"); i = hdr->h_scha&0377; printf("H.SCHA %03o = ", i); if(i & SC_MDL) printf("SC.MDL = Marked for delete "); if(i & SC_BAD) printf("SC.BAD = Bad blocks within "); if(i & SC_DIR) printf("SC.DIR = Directory file "); if(i & SC_SPL) printf("SC.SPL = Spool int. file "); printf("\n"); printf("H.UCHA: User defined attributes (FCS format)\n"); i = ufp->f_rtyp&0377; printf("\tF.RTYP %03o = ", i); if(i == 0) printf("UNDEF"); if(i == R_FIX) printf("R.FIX"); if(i == R_VAR) printf("R.VAR"); if(i == R_SEQ) printf("R.SEQ"); i = ufp->f_ratt&0377; printf(" F.RATT %03o = ", i); if(i == 0) printf("NONE"); if(i & FD_FTN) printf("FD.FTN"); if(i & FD_CR) printf("FD.CR"); if(i & FD_PRN) printf("FD.PRN"); if(i & FD_BLK) printf(",FD.BLK"); printf("\n"); i = ufp->f_rsiz; printf("\tF.RSIZ %06o = %d.\n", i, i); j = ufp->f_hibk; printf("\tF.HIBK %07lo [ H:%03o L:%06o ] = %ld.\n", j, j, j); j = ufp->f_efbk; printf("\tF.EFBK %07lo [ H:%03o L:%06o ] = %ld.\n", j, j, j); i = ufp->f_ffby; printf("\tF.FFBY %03o = %d.\n", i, i); printf("\tRest of user attributes:\n\t"); for(i=0; i<18;) { printf("%03o ", ufp->f_crap[i++]); if(i%8 == 0) printf("\n\t"); } printf("\n\nIdent area:\n"); r50toa(fn, hdr->i_fnam, 3); fn[9] = '\0'; printf("I.FNAM: %s\n", fn); r50toa(fn, hdr->i_ftyp, 1); fn[3] = '\0'; printf("I.FTYP: %s\n", fn); printf("I.FVER = %o (octal)\n", hdr->i_fver); printf("I.RVNO = %o (octal)\n", hdr->i_rvno); printf("I.RVDT: "); p = hdr->i_rvdt; for(i=0; i<7; i++) putchar(*p++); printf(" I.RVTI: "); p = hdr->i_rvti; for(i=0; i<6; i++) putchar(*p++); printf("\nI.CRDT: "); p = hdr->i_crdt; for(i=0; i<7; i++) putchar(*p++); printf(" I.CRTI: "); p = hdr->i_crti; for(i=0; i<6; i++) putchar(*p++); printf("\nI.EXDT: "); p = hdr->i_exdt; for(i=0; i<7; i++) putchar(*p++); printf("\n\nMap Area:\n"); printf("M.ESQN %03o M.ERVN %03o\n", hdr->m_esqn&0377, hdr->m_ervn&0377); printf("M.EFNU,M.EFSQ = (%06o,%06o)\n", hdr->m_efnu, hdr->m_efsq); printf("M.CTSZ %03o M.LBSZ %03o\n", hdr->m_ctsz&0377, hdr->m_lbsz&0377); i = hdr->m_max&0377; k = hdr->m_use&0377; printf("M.USE %03o M.MAX %03o\n", k, i); printf("M.RTRV: Retrieval Pointers (%d maximum)\n", i/2); for(i=0; i long extends sign ) */ j = ((hdr->m_map[i]&0377l)<<16) + (hdr->m_map[i+1]&0177777l); printf ( "Segment %3d: Size = %3d. LBN %07lo [ H:%03o L:%06o ] = %ld.\n", i/2+1, ((hdr->m_map[i]>>8)&0377)+1, j, j, j ); } printf("\nH.CKSM = %06o\n", hdr->h_cksm); } /* * Here, we handle multi-header files. If there is at least 1 extension * file, we assign LUN fn+1 to the same device as the primary file, do * a read attributes to the extension file ID, and loop back through the * header dump code. We keep this up till there is no extension file * indicated. We use the M.ESQN value in efn. Sorry about the hacking * in the FDB, referring to it as an array, rather than a struct. */ if(hdr->m_efnu != 0) /* Is there an(other) ext. file? */ { if(efn == 0) /* Assign LUN only once */ { efl = fl+1; alun(efl, fp->io_fdb[46], fp->io_fdb[47]); } hdr->m_ctsz = hdr->m_lbsz = 1; /* Fake a full FID for ext. file */ ratpar[0] = &(hdr->m_efnu); /* Point to the extension FID */ qiow(IO_RAT,efl,15,0,0,ratpar); /* Read the extension header */ efn = (hdr->m_esqn ? hdr->m_esqn : 1); /* Avoid loop on QIO fail */ goto hdrdump; /* Dump out the extension header */ } #endif if(aflag || bflag || fflag || wflag || xflag) dump(bp); } /* * Do the dump. * `bp' is the banner string * (either "block" or "record"). */ dump(bp) char *bp; { register int n; long rn; long place; long ftell(); rn = 1l; /* VBN's start with 1 */ if(!blkmode) /* Advance record file to first rec. */ { while(rn < fbn) { fget(buf, max_size, fp); if(feof(fp)) return; rn++; } } while(rn <= lbn) { if(blkmode) { rvbpar.vbn = rn; qiow(IO_RVB,fl,15,iosb,0,&rvbpar); if(iosb[0] != IS_SUC) return; n = iosb[1]; } else { place = ftell(fp) + 1l; n = fget(buf, max_size, fp); if(feof(fp)) return; } /* * The format has been modified, taking into * account the current ODS-1 LBN limit of 1,048,576 (4,000,000 octal), * and the filespec has been added. Also, it varies between device * types and formats. * (RBD) */ printf("\n\n** DUMP OF %s\n", fspec); if(blkmode) printf("%s %ld. [ H:%03o L:%06o ] Length = %d. bytes\n\n", bp, rn, rn, n); else if(frec(fp)) printf("%s %ld. Length = %d. bytes\n\n", bp, rn, n); else printf( "%s %ld. Length = %d. bytes VBN %ld. [ H:%03o L:%07o ] Byte %03lo\n\n", bp, rn, n, place>>9, place>>9, (place&0777l)+1l); format(buf, n); rn++; } } /* * Dump out an `n' byte * item according to the flags * set by the user. */ format(ap, n) char *ap; { register int *wp; register char *bp; register int i; int o, of, nb, c; char ab[3], *fmt; if(!bflag && !wflag && xflag) fmt = "%04x "; else fmt = "%06o"; o = 0; while(n) { nb = min(16, n); of = 1; if(wflag) { printf(fmt, o); of = 0; printf(" w"); wp = ap; i = ((nb+1)&017776)/2; /* FIX for odd size rec's */ while(i--) printf(" %06o", *wp++); putchar('\n'); } if(aflag) { if(of) { printf(fmt, o); of = 0; } else printf(" "); printf(" a"); bp = ap; i = nb; while(i--) { c = *bp++ & 0377; if(c<' ' || c>'~') printf(" %03o", c); else printf(" %c", c); } putchar('\n'); } if(bflag) { if(of) { printf(fmt, o); of = 0; } else printf(" "); printf(" b"); bp = ap; i = nb; while(i--) printf(" %03o", *bp++ & 0377); putchar('\n'); } if(fflag) { if(of) { printf(fmt, o); of = 0; } else printf(" "); printf(" 5"); wp = ap; i = nb/2; while(i--) { r50toa(ab, wp++, 1); printf(" %.3s", ab); } putchar('\n'); } if(xflag) { if(of) printf(fmt, o); else printf(" "); printf(" x"); bp = ap; i = nb; while(i--) printf(" %02x", *bp++ & 0377); putchar('\n'); } o += 16; ap += 16; n -= nb; } } /* * Compute the minimum of * two numbers. * Should be in the library. */ min(a, b) { if(a < b) return(a); return(b); } /* * Cannot open diagnostic. * Just exit. */ cant(p) char *p; { fprintf(stderr, "%s: cannot open\n", p); exit(1); } /* * Usage diagnostic. * Just exit. */ usage() { fprintf(stderr, "Usage: dump [-5abrwx] [-f bn] [-l bn] file\n"); exit(1); }