Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_3_19910112 - utilities/dskop.fai
There are no other files named dskop.fai in the archive.
;ACCT:<JQJ>DSKOP.FAI.16,  9-Sep-80 09:11:37, Edit by J.JQJOHNSON
;fix up user symbols and loading instructions
;ACCT:<JQJ>DSKOP.FAI.13,  8-Sep-80 17:12:54, Edit by J.JQJOHNSON
;install DDT as top level, and some cleanup

	TITLE	DSKOP -- PROWL THE DISK
	SEARCH	MONSYM

	extern ddt,.jbsym,.jbusy,.jbddt

;loading instructions:
;	LOAD SYS:DDT.REL %"NOLOCALS",SYS:MONSYM.REL,DSKOP.FAI
;	SAVE DSKOP
;Note that DDT was chosen as the top level command parser for this
;program because one typical use of the program is to modify the
;image of a file using DDT then to write the image back to the disk.

;ACs
FLAG=0
	F.POCT==1		;print octal contents of file
A=1
B=2
C=3
D=4
W=5

P=17				;of course...


OPDEF	RET	[POPJ P,]
OPDEF	CALL	[PUSHJ P,]
	subttl data

PDLEN=100
PDLIST:	BLOCK	PDLEN
DIRNUM:	0

npage==100				;maximum number of pages to read
ipage==100000				;address for index page
dpage==200000				;address for start of data
ifle <1000-<dpage/1000>-npage>,<
	.fatal NPAGE is too big to fit.
>

CRLF:	BYTE(7)15,12

GTJFNT:	GJ%OLD!GJ%IFG!GJ%FLG!GJ%XTN!GJ%CFM ;FLAGS
	.PRIIN,,.PRIOU		;jfn from terminal
	0			;device
	0			;directory
	0			;name
	0			;ext
	0			;prot
	0			;acct
	0			;jfn to get
	4			;number of wds following
	0			;string pointer
	0			;string count
	0			;^R buffer
	0			;destination buffer


FDB:	BLOCK	40		;note that we need extra room for
				;long FDBs
JFN:	0			;jfn for file to prowl
OJFN:	0			;jfn for file to write results to

STCODE:0
STRNAM:	BLOCK 10
LOC:	0
ALOC:	0
MAXLOC:	0
NAMBUF:	BLOCK	2
SJFN:	0
HEADER:	BLOCK	4
ECOUNT:	0

BUFLEN==10
IBUFR:	BLOCK	BUFLEN
DSKADR:	0
	subttl main program

START:	RESET				;start this way
	MOVE	P,[IOWD PDLEN,PDLIST]
	HRROI A,[asciz/Type  CALL HELP<alt>X for help.
/]
	PSOUT
	MOVEI A,DDT
	MOVEM A,.JBDDT		;save DDT start addr for DDT commands later
	MOVE B,.JBSYM		;get symbol table
	MOVEM B,@1(A)		;store it where it belongs
	MOVE B,.JBUSY		;get user symbols
	MOVEM B,@2(A)		;store it where it belongs
	JRST (A)		;and go start DDT
	subttl HELP, READ, and WRITE commands

;HELP command
HELP:	HRROI A,[ASCIZ/
  You are talking to DDT, the top level for this program.  To execute
a command, type CALL followed by the name of the subroutine you want
to execute, followed by ESCAPE (ALTMODE) and the letter X, e.g.:
	CALL HELP$X

  The subroutine will return to DDT via a RET (popj 17,0).
Routines currently available include:
HELP	prints this message
PRINT	reads a file or files (wildcards ok) using DSKOP%, printing
	the contents in octal in DSKOP.OUT.  If a directory (FB%DIR
	set in its FDB) interprets the file as a directory, and
	prints the directory in DSKOP.OUT (like DIRPNT).
READ	reads a file using DSKOP%.  Saves the current file in
	DPAGE..DPAGE+n*1000 with index pages in IPAGE..IPAGE+n
WRITE	writes the current file starting at DPAGE to addresses specified
	starting at IPAGE, assuming they are valid.
ISCAN	looks at the lost pages file that CHECKD writes.  For each disk
	address that's found there check to see if it looks like it might
	be an index page.  If it's an index page, you can guess at the
	name of the file, and reconstruct all the necessary parts of an
	FDB by hand.   Everything considered, it would have been a better
	idea to be on vacation when your disaster happened.
READA	Read Absolute.  Command prompts for channel, unit, record.
	Reads four records into DPAGE.

A typical use of the program would be to READ a file, then modify it
	using DDT commands (note that it is mapped starting at DPAGE),
	then WRITE it again./]
	PSOUT
	RET

READA:	HRROI	A,[ASCIZ/Channel #/]
	CALL	PRMGOC			;prompt & get octal.
	MOVSI	A,200000		;set for absolute address
	MOVEM	A,DSKADR
	DPB	B,[Point 5,DSKADR,6]	;Store in disk address
	HRROI	A,[ASCIZ/Unit # /]
	CALL	PRMGOC
	DPB	B,[Point 6,DSKADR,12]
	HRROI	A,[ASCIZ/Record # /]
	CALL	PRMGOC
	DPB	B,[Point 23,DSKADR,35]
	MOVE	A,DSKADR
	MOVEI	B,1000
	MOVEI	C,DPAGE
	DSKOP
	JUMPN	A,[PUSH P,A
		HRROI A,[ASCIZ/Lose: /]
		PSOUT
		POP P,B
		MOVEI A,.PRIOU
		MOVEI C,10
		NOUT
		JFCL
		HRROI A,CRLF
		PSOUT
		RET]
	HRROI	A,[ASCIZ/Ok.  Result at DPAGE
/]
	PSOUT
	RET

PRMGOC: PUSH	P,A
PRMGO1:	MOVE	A,(P)
	MOVE	C,A
	PSOUT
	HRROI	A,IBUFR
	MOVEI	B,BUFLEN*5-1
	RDTTY
	ERJMP	ERCOMM
	HRROI	A,IBUFR
	MOVEI	C,10
	NIN
	ERJMP	[HRROI A,[ASCIZ/Error in Number.  Octal please.
/]
		PSOUT
		JRST	PRMGO1]
	POP	P,A
	RET

;READ command
READ:	TRZ FLAG,F.POCT		;don't print in octal
	CALL GTFILE		;get file name, and open DSKOP.OUT etc.
	CALL READ1F		;set up to read the contents of the file
	CALL RDFILE		;read file (or sub-indicies)
	JRST DONE1		;close output file


;WRITE command
WRITE:	JRST WTFILE		;write the file
	subttl PRINT command

;PRINT command -- read and print the contents of a file or files.
PRINT:	CALL GTFILE		;get file name, and open DSKOP.OUT etc.
	TRO FLAG,F.POCT		;print in octal (used by rdfile)

;here to loop over the given file specification, in case of wild cards
JLP:	CALL	READ1F		;set up to read one file
	PUSHJ	P,RDFILE		;read file (or sub-indicies)
	MOVEI	A,DPAGE
	MOVEM	A,LOC
BR:	MOVE	A,FFBCTL
	TLNE	A,(FB%DIR)		;skip unless directory file
	CALL	DIRPNT			;interpret directory file.
	MOVE	A,JFN
	GNJFN				;GET NEXT JFN
	 JRST	DONE1
	HRROI	B,[BYTE(7)15,12,12,14]
	CALL	PSTR			;new page between files
	JRST	JLP			;CONTINUE

DONE1:	HRRZ	A,OJFN		;close up the output jfn
	CLOSF
	 ERJMP	ERCOMM
	RET
;get a file specification, storing its jfn in JFN.  Open DSKOP.OUT
;for results.
GTFILE:	HRROI	A,[ASCIZ/Name of file to prowl: /]
	MOVEM	A,GTJFNT+.GJRTY		;CTRL/R REPROMPT
	PSOUT
	MOVEI	A,GTJFNT		;GTJFN TABLE
	MOVEI	B,0
	GTJFN				;get file spec
	 ERJMP	ERCOMM
	MOVEM	A,JFN			;save jfn
	HRROI	A,CRLF
	PSOUT
	MOVSI	A,(GJ%FOU!GJ%SHT) 	;Open DSKOP.OUT for our results
	HRROI	B,[ASCIZ/DSKOP.OUT/]
	GTJFN
	 ERJMP	ERCOMM
	MOVEM	A,OJFN
	MOVE	B,[070000,,OF%WR]
	OPENF
	 ERJMP	ERCOMM
	RET

;read one file
;assume JFN is in JFN.
READ1F:	HRRZ	B,JFN			;type current filename
	MOVEI	A,.PRIOU		;output
	movei	c,0
	JFNS
	 ERJMP .+1
	HRROI	A,CRLF
	PSOUT
	HRROI	B,[ASCIZ/Prowling file /]
	CALL	PSTR
	HRRZ	B,JFN		;A and C set by PSTR
	JFNS
	 ERJMP	.+1
	HRROI	B,CRLF
	CALL	PSTR
	HRROI	A,STRNAM		;get current structure name
	HRRZ	B,JFN
	MOVE	C,[100000,,0]		;device name no punct?
	JFNS
	 ERJMP	.+1
	HRROI	A,STRNAM		;convert to structure ID code
	STDEV				;or device number
	 ERJMP	ERCOMM
	MOVEM	B,STCODE		;structure ID code

	HRRZ	A,JFN			;get the FDB of the file.
	MOVE	b,[30,,0]
	MOVEI	C,FDB
	GTFDB				;read FDB
	move	a,fdb+.fbctl
	MOVEM	A,FFBCTL#		;main file's FBCTL
	tlnn	a,(fb%lng)		;long file?
	jrst	jlp1
	HRROI	A,[ASCIZ/Warning: this is a long file.
We'll be reading the index pages instead of the data!  Good luck
/]
	PSOUT
jlp1:	move	a,fdb+.FBADR		;get the disk address
	IOR	 A,[BYTE(2)2(9)777]	;STRUCTURE RELATIVE.  STRU DESIGN IN AC4
	MOVEI	B,1000			;read index page
	MOVEI	C,IPAGE			;ADDRESS to read to
	MOVE	D,STCODE		;device ID for given structure
op:	DSKOP				;here we read the index table
	JUMPN	A,ERCOMM
	call	cmpchk			;does checksum match?
	 JRST	CHKBAD			;nope.
OK:	HRROI	A,[ASCIZ/[Index page checksum is ok]
/]
	PSOUT
	JRST	OK1

CHKBAD:	HRROI	A,[ASCIZ/[Index page checksum is incorrect.]
Type CONTINUE to use this data anyway./]
	ESOUT
	HALTF
OK1:	RET
ERCOMM:	PUSHJ	P,ERPMS	
	HALTF
	JRST	START	

ERPMS:	PUSH	P,A
	PUSH	P,B
	PUSH	P,C
	HRROI	A,CRLF
	PSOUT
	MOVEI	A,.PRIOU
	HRLOI	B,.FHSLF		;fork,,-1
	MOVEI	C,0
	ERSTR
	HRROI	A,CRLF
	PSOUT
	POP	P,C
	POP	P,B
	POP	P,A
	POPJ	P,
	subttl rdfile and wtfile

;read file.  Reads first NPAGE pages described by IPAGE into DPAGE
;writes each page in octal to output file if F.POCT is set.
rdfile:	movsi	W,-NPAGE		;a small number of pages to read
rdfil1:	move	a,ipage(W)
	tlnn	a,10			;skip if this is a disk address
	jrst	rdfil2			;not this page
	and	a,[77,,-1]
	IOR	A,[BYTE(2)2(9)777]		;MAKE IT STRUCTURE RELATIVE
	movei	b,1000			;count of words
	movei	c,(W)			;page number to read
	lsh	c,9			;word number of file
	addi	c,dpage			;offset to data area
	MOVEM	C,LOC			;FIRST LOC OF THIS PAGE
	IORI	C,777
	MOVEM	C,MAXLOC
	TRZ	C,777
	MOVE	D,STCODE		;STRUCTURE NAME
	DSKOP
	JUMPE	A,RDFIL3		;jump if ok
	PUSHJ	P,ERPMS
	JRST	RDFIL2

RDFIL3:	TRNE	FLAG,F.POCT
	 CALL	PPAGE			;print in octal to listing
RDFIL2:	AOBJN	W,RDFIL1		;do another page
RDSTOP:	POPJ	P,
;wtfile -- write out the current file
;as rdfile: writes data at DPAGE according to first NPAGE words of IPAGE
wtfile:	movsi	W,-NPAGE		;a small number of pages to write
wtfil1:	move	a,ipage(W)
	tlnn	a,10			;skip if this is a disk address
	jrst	wtfil2			;not this page
	and	a,[77,,-1]
	IOR	A,[BYTE(2)2(9)777]		;MAKE IT STRUCTURE RELATIVE
	MOVE	B,[DOP%WR!1000]		;write bit + word count
	movei	c,(W)			;page number to read
	lsh	c,9			;word number of file
	addi	c,dpage			;offset to data area
	MOVE	D,STCODE		;STRUCTURE NAME
	DSKOP
	JUMPE	A,WTFIL2		;jump if ok
	PUSHJ	P,ERPMS
WTFIL2:	AOBJN	W,WTFIL1
	RET
	subttl useful subroutines -- swap, cmpchk,

;swap:  call with A=low address, B= high address.  all in
;range will be swapped. (MOVSS).   May you be lucky with your channels

SWAP:	MOVSS	(A)
	CAMGE	A,B
	AOJA	A,SWAP
	RET


;cmpchk -- checksum the index block at ipage
;ret:	+1 checksum incorrect
;	+2 normally
cmpchk:	MOVE	B,[-1000,,IPAGE]
	CALL	GETCHK		;checksum to C
	LDB	B,[POINT 9,IPAGE,8]
	DPB	B,[POINT 9,A,8]
	LDB	B,[POINT 9,IPAGE+1,8]
	DPB	B,[POINT 9,A,17]
	LDB	B,[POINT 9,IPAGE+2,8]
	DPB	B,[POINT 9,A,26]
	LDB	B,[POINT 9,IPAGE+3,8]
	DPB	B,[POINT 9,A,35]
	CAMN	C,A
	aos	(p)			;checksum is ok.
	ret

;GET CHECKSUM.  Computes Checksum given AOBJN pointer in B.
;clobbers a, b,   result in C

GETCHK:	MOVEI	C,0			;initial checksum
	JFCL	17,.+1			;clear all flags
GETCK1:	LDB	A,[POINT 27,(B),35]	;get disk address
	JUMPN	A,GETCK2		;we have a disk address
	HLRE	A,B			;for zero, compute
	ADDI	A,777			;the address within the page
GETCK2:	ADD	C,A			;sum the sum
	JCRY0	[AOJA C,.+1]		;in case of carry, bump count
	AOBJN	B,GETCK1		;loop
	RET
	subttl printing routines
PLINE:	HRRZ	A,OJFN
	HRRZ	B,LOC
	SUBI	B,DPAGE
	MOVE	C,[NO%LFL!<6,,10>]
	NOUT
	 ERJMP	.+1
	HRRZ	A,OJFN
	MOVEI	B,"/"
	BOUT
	 ERJMP	.+1
	MOVEI	W,0
	MOVSI	D,-10
	HRR	D,LOC
PLIN1:	HRRZ	A,OJFN
	MOVEI	B,11
	BOUT
	 ERJMP	.+1
	HRRZ	A,OJFN
	MOVE	B,(D)
	IOR	W,B
	MOVE	C,[NO%MAG!NO%LFL!NO%ZRO+<14,,10>]
	NOUT
	 ERJMP	.+1
	AOBJN	D,PLIN1
	HRRZ	A,OJFN
	MOVEI	B,15
	BOUT
	MOVEI	B,12
	BOUT
CPOPJ:	RET


PPAGE:	PUSH	P,W
PPAGE1:	CALL	PLINE
PPAGE2:	MOVEI	A,10
	ADDB	A,LOC
	TRNN	A,777
	JRST	PPAGE3
	JUMPN	W,PPAGE1		;PRINT NEXT LINE
	MOVSI	D,-10
	HRR	D,LOC
PPAG2A:	SKIPE	(D)
	JRST	PPAGE1
	AOBJN	D,.-2
	JRST	PPAGE2			;DON'T PRINT ALL ZERO

PPAGE3:	POP	P,W
	RET
	subttl dirpnt -- interpret a directory

DIRPNT:	HRROI	B,[Byte (7)15,12,12,14]
	CALL	PSTR
	HRROI	B,[ASCIZ/Interpretation of file /]
	CALL	PSTR
	HRRZ	B,JFN
	JFNS
	 ERJMP	.+1
	HRROI	B,[ASCIZ/ as a directory file

/]
	CALL	PSTR
DIRPN0:	MOVE	W,LOC
	CAML	W,MAXLOC
	RET
	HLRZ	A,(W)			;FIRST WORD OF DIR BLK
	CALL	DIDISP			;DISPATCH IF POSSIBLE
	CALL	DIRERR			;ILLEGAL TYPE.  SKIP IFPOSSIBLE
	JRST	DIRPN0

DIDISP:	MOVSI	C,-DIDSPL
DIDSP1:	HLRZ	B,DIDSPT(C)
	CAMN	A,B
	JRST	DIDSP2
	AOBJN	C,DIDSP1
	RET

DIDSP2:	HRRZ	B,DIDSPT(C)
	LDB	D,[POINT 12,0(W),35]	;length of this block
	ADDM	D,LOC			;ADVANCE TO NEXT BLOCK
	MOVN	D,D
	HRL	W,D			;-COUNT,,ADDRESS OF CURRENT BLOCK
	AOS	(P)
	JRST	(B)

DIDSPT:	400001,,.TYNAM			;file name block
	400002,,.TYEXT			;file type block
	400003,,.TYACT			;account string block
	400004,,.TYUNS			;USER NAME STRING
	400100,,.TYFDB			;file descriptor block
	400200,,.TYLAC			;LEGAL ACCOUNT LIST
	400300,,.TYDIR			;DIRECTORY HEADER
	400400,,.TYSYM			;SYMBOL TBALE
	400500,,.TYFRE			;BLOCK ON FREE LIST
	400600,,.TYFBT			;FREE STORAGFE BIT TABLE
	400700,,.TYGDB			;GROUP DECRIPTOR BLOCK
DIDSPL==.-DIDSPT

DIRERR:	HRROI	B,[ASCIZ/*******************************   Unknown type:  /]
	CALL	PSTR
	HLRZ	B,@LOC
	CALL	PLOC
	HRROI	B,[ASCIZ/ AT LOCATION /]
	CALL	PSTR
	HRRZ	B,LOC
	CALL	PLOCL
	HRROI	B,CRLF
	CALL	PSTR
	MOVE	B,LOC
	TRZ	B,7
	MOVEM	B,ALOC
DIRER1:	MOVE	B,ALOC
	CALL	PLOCL
	MOVEI	B,"/"
	CALL	PCHR
DIRER2:	MOVEI	B,11
	CALL	PCHR
	MOVE	A,ALOC
	CAMGE	A,LOC
	JRST	[CALL PCHR
		JRST DIRER3]
	MOVE	B,@ALOC
	CALL	POCT
	HLRZ	A,@ALOC
	MOVSI	C,-DIDSPL
DRER2A:	HLRZ	B,DIDSPT(C)
	CAMN	A,B
	JRST	DRER2B
	AOBJN	C,DRER2A
	JRST	DIRER3

DRER2B:	MOVE	A,ALOC
	MOVEM	A,LOC
	HRROI	B,CRLF
	CALL	PSTR
	RET

DIRER3:	AOS	A,ALOC
	TRNE	A,7
	JRST	DIRER2
	HRROI	B,CRLF
	CALL	PSTR
	MOVE	A,ALOC
	CAMGE	A,MAXLOC
	JRST	DIRER1
	MOVEM	A,LOC
	RET

PSTR:	MOVEI	C,0
	HRRZ	A,OJFN
	SOUT
	 ERJMP	.+1
	RET

PCHR:	HRRZ	A,OJFN
	BOUT
	 ERJMP	.+1
	RET

POCT:	HRRZ	A,OJFN
	MOVE	C,[no%mag!NO%LFL!NO%ZRO+<14,,10>]
	NOUT
	 ERJMP	.+1
	RET

PLOCL:	SUBI	B,DPAGE
PLOC:	HRRZ	A,OJFN
	MOVE	C,[NO%LFL+<6,,10>]
	NOUT
	 ERJMP	.+1
	RET


.TYNAM:	CALL	PLOCLW
	HRROI	B,[ASCIZ/File name: /]
.TYASZ:	CALL	PSTR
	HRROI	B,1(W)
	CALL	PSTR
PCRLF:	HRROI	B,CRLF
	JRST	PSTR

.TYEXT:	CALL	PLOCLW
	HRROI	B,[ASCIZ/File Type: /]
	JRST	.TYASZ

PLOCLW:	HRRZ	B,W
	CALL	PLOCL
	HRROI	B,[ASCIZ\/	\]
	JRST	PSTR

.TYACT:	CALL	PLOCLW
	HRROI	B,[ASCIZ/Account name: "/]
.TYSHR:	CALL	PSTR
	HRROI	B,2(W)
	CALL	PSTR
	HRROI	B,[ASCIZ/"    Share count = /]
	CALL	PSTR
	MOVE	B,1(W)
	CALL	POCT
	JRST	PCRLF


.TYUNS:	CALL	PLOCLW
	HRROI	B,[ASCIZ/User name: "/]
	JRST	.TYSHR

.TYFDB:	CALL	PLOCLW
	HRROI	B,[ASCIZ/File Descriptor Block
/]
	CALL	PSTR
	CALL	PFDB
	RET


.TYFRE:	CALL	PLOCLW			;print current location
	HRROI	B,[ASCIZ/Free Space, through /]
	CALL	PSTR
	MOVE	B,LOC			;address of next block
	SUBI	B,1			;end of this block
	CALL	PLOCL			;print as relative
	SKIPE	1(W)			;is there another free blk
	JRST	TYFRE1			;yes
	HRROI	B,[ASCIZ/.  No next free block on this page/]
	CALL	PSTR
	JRST	PCRLF			;and leave

TYFRE1:	HRROI	B,[ASCIZ/;  next free block at /]
	CALL	PSTR
	MOVE	B,1(W)			;data from block
	CALL	POCT			;print address
	HRRZ	A,W			;compute present page origin
	SUBI	A,DPAGE
	XOR	A,1(W)			;mark off page bits in pointer
	TDNN	A,[-1,,777000]		;make sure no cross page.
	JRST	TYFRE2			;it's ok.
	HRROI	B,[ASCIZ/
************************************** this address crosses page
/]
	JRST	PSTR

TYFRE2:	MOVEI	A,400500		;check on things
	MOVE	B,1(W)
	CALL	CHKADR			;check address is ok.
	 JFCL				;a message was printed.
	JRST	PCRLF


.TYLAC:	CALL	PLOCLW
	HRROI	B,[ASCIZ/Legal Account Block
/]
	CALL	PSTR
	RET

.TYDIR:	CALL	PLOCLW
	HRROI	B,[ASCIZ/Directory Header Block.  Page Number /]
	CALL	PSTR
	HLRZ	B,1(W)		;PN
	HRRZ	A,W		;location of data
	SUBI	A,DPAGE		;relative location
	LSH	A,-9		;convert to page number
	CAMN	A,B
	JRST	TYDIR0
	HRROI	B,[ASCIZ/ (bad page number) /]
	CALL	PSTR
	HLRZ	B,1(W)		;print bad page number
TYDIR0:	CALL	PLOC
	HRROI	B,[ASCIZ/   Directory Number /]
	CALL	PSTR
	HRRZ	B,1(W)
	HRRZ	A,W
	CAIN	A,DPAGE
	MOVEM	B,DIRNUM	;this is the real directory number??
	CAMN	B,DIRNUM	;is this the same as before?
	JRST	TYDIR1		;yes
	HRROI	B,[ASCIZ/ (different from first time!!!) /]
	CALL	PSTR
	HRRZ	B,1(W)
TYDIR1:	CALL	PLOC
	CALL	PCRLF
	SKIPN	B,2(W)		;free space pointer.
	JRST	TYDIR3		;no print for zero
	HRROI	B,[ASCIZ/Free storage pointer = /]
	CALL	PSTR
	MOVE	B,2(W)
	CALL	POCT
	HRRZ	A,W		;Check this FS pointer
	SUBI	A,DPAGE		;A:=page number within dir
	XOR	A,2(W)		;XOR against this pointer
	TDNN	A,[-1,,777000]
	JRST	TYDIR2		;it's on the right page
	HRROI	B,[ASCIZ/ ************* this points off the current page/]
	CALL	PSTR
	JRST	TYDIR3		;don't bother to look.

TYDIR2:	MOVEI	A,400500	;check for right type.
	CALL	CHKADR
	 JFCL			;it already barfed
	CALL	PCRLF
TYDIR3:	HRRZ	A,W
	CAIE	A,DPAGE		;page zero?
	RET			;short block
	ADD	W,[3,,3]	;advance past DRTYP,DRNUM,DRFFB
	JUMPG	W,CPOPJ		;exit if this is a short block
	MOVEI	A,3
	MOVEM	A,ALOC		;relative word number in page
TYDIR4:	SKIPE	(W)		;is data item zero?
	JRST	TYDIR5		;nope.  print something
	MOVE	A,ALOC		;relative location inside FDB
	CAIL	A,.DRTLN	;is it a known location?
	JRST	TYDIR9		;no.  suppress zero TYO
	HLRZ	A,.DRFMT(A)	;get the dispatch address
	CAIE	A,CPOPJ
	CAIN	A,PDAT
	JRST	TYDIR9		;suppress TYO for zero
TYDIR5:	HRROI	B,[ASCIZ/    /]
	CALL	PSTR
	HRRZ	B,ALOC		;print relative locn in FDB
	CALL	PLOC
	HRROI	B,[ASCIZ\/  \]
	CALL	PSTR
	MOVE	A,ALOC		;current location
	CAIL	A,.DRTLN	;special printing?
	JRST	TYDIR6		;normal printing
	HRRO	B,.DRFMT(A)	;message for this address
	CALL	PSTR
	MOVE	A,ALOC
	MOVE	B,(W)
	CALL	POCT		;always print octal
	HRROI	B,[ASCIZ/  /]
	CALL	PSTR
	MOVE	A,ALOC		;pseudo loc count
	MOVE	B,(W)		;datum
	HLRZ	A,.DRFMT(A)
	CALL	(A)
	CALL	PCRLF
	JRST	TYDIR9

TYDIR6:	HRROI	B,[ASCIZ/		/]
	CALL	PSTR
	MOVE	B,(W)
	CALL	POCT
	CALL	PCRLF
TYDIR9:	AOS	ALOC
	AOBJN	W,TYDIR4
	CALL	PCRLF
	RET

.DRFMT:	0			;already did the header
	0			;the relative page & dir num
	0			;free stg pointer
	CPOPJ,,[ASCIZ/Symbol table Bottom            /]
	CPOPJ,,[ASCIZ/Symbol table Top               /]
	CPOPJ,,[ASCIZ/Address of first free word     /]
	CPOPJ,,[ASCIZ/Address of free pool bit table /]
	CPOPJ,,[ASCIZ/Default file protection        /]
	CPOPJ,,[ASCIZ/Default directory protection   /]
	CPOPJ,,[ASCIZ/Backup specification           /]
	CPOPJ,,[ASCIZ/Working quota                  /]
	CPOPJ,,[ASCIZ/Permanent quota                /]
	CPOPJ,,[ASCIZ/Current space allocation       /]
	CPOPJ,,[ASCIZ/Pointer to name string         /]
	CPOPJ,,[ASCIZ/Pointer to password string     /]
	CPOPJ,,[ASCIZ/Capabilities                   /]
	CPOPJ,,[ASCIZ/Mode word                      /]
	 PDAT,,[ASCIZ/Date of last login             /]
	CPOPJ,,[ASCIZ/User groups                    /]
	CPOPJ,,[ASCIZ/Directory Groups               /]
	 PDAT,,[ASCIZ/Last directory update          /]
	CPOPJ,,[ASCIZ/Number of subdirectories       /]
	CPOPJ,,[ASCIZ/Maximum number of subdirs      /]
	CPOPJ,,[ASCIZ/Allowable user groups ???      /]
	CPOPJ,,[ASCIZ/Default account string         /]
.DRTLN==.-.DRFMT

.TYFBT:	CALL	PLOCLW
	HRROI	B,[ASCIZ/Free Storage Bit Table  /]
	CALL	PSTR
	MOVE	B,1(W)
	CALL	POCT
	JRST	PCRLF

.TYGDB:	CALL	PLOCLW
	HRROI	B,[ASCIZ/Group Descriptor Block
/]
	JRST	PSTR

FDBFMT:	CPOPJ,,[ASCIZ/FDB Header          /]
	PFBCTL,,[ASCIZ/.FBCTL              /]	;TMP!PERM!NON-EX!DELETED!NXF!LONG!DIREC
	PNFB,,[ASCIZ/FDB of next type    /]
	padr,,[ASCIZ/Index Blk Addr      /]
	pprot,,[ASCIZ/File Protection     /]
	PDAT,,[ASCIZ/Last Write Date     /]
	PAUT,,[ASCIZ/Author              /]
	pgen,,[ASCIZ/Gen,,Dir Num        /]
	PACT,,[ASCIZ/Account Number      /]
	cpopj,,[ASCIZ/File Pg Cnt, etc.   /]
	pbct,,[ASCIZ/File Byte Count     /]
	PDAT,,[ASCIZ/Creation Date       /]
	PDAT,,[ASCIZ/Write Date          /]
	PDAT,,[ASCIZ/Reference Date      /]
	cpopj,,[ASCIZ/Wrt Cnt,,Rd Cnt     /]
	cpopj,,[ASCIZ/Dump word 17        /]
	cpopj,,[ASCIZ/Dump word 20        /]
	cpopj,,[ASCIZ/Dump word 21        /]
	cpopj,,[ASCIZ/Dump word 22 (arc)  /]
	pdat,,[ASCIZ/Online expiration   /]
	cpopj,,[ASCIZ/User word           /]
	PNFB,,[ASCIZ/FDB of next Gen     /]
	PNAM,,[ASCIZ/File name           /]
	PEXT,,[ASCIZ/File type           /]
	PAUT,,[ASCIZ/Last writer         /]
	pdat,,[asciz/Archive date        /]
	pdat,,[asciz/Offline expiration	 /]
	cpopj,,[asciz/Archive tape ID 1	  /]
	cpopj,,[asciz/Saveset (tape 1)	  /]
	cpopj,,[asciz/Archive tape ID 2	  /]
	cpopj,,[asciz/Saveset (tape 2)	  /]
FDBTLN==.-FDBFMT			;length of format table....

PLAC:
	SETZM	ALOC
POCTL:	HRRZ	B,ALOC
	CALL	PLOC
	HRROI	B,[ASCIZ\/	\]
	CALL	PSTR
	MOVE	B,(W)
	CALL	POCT
	CALL	PCRLF
	AOS	ALOC
	AOBJN	W,POCTL
	RET

pprot:	hlrz a,b
	cain a,500000		;LH must be ok
	RET
	hrroi b,[asciz/ (invalid LH)/]
	jrst pstr

pbct:	ret			;for now.

;print the generation  number
pgen:	hrrz a,b
	jumpe a,PGEN1		;not a directory
	MOVE	A,SFBCTL
	TDNN	A,[FB%DIR]	;bit must be set
	JRST	PGENB1		;bad
	hrroi b,[asciz/ (this is a directory file)/]
	jrst pstr

PGENB1:	HRROI	B,[ASCIZ/ ****** directory number set, but not FB%DIR/]
	JRST	PSTR


PGEN1:	MOVE	A,SFBCTL
	TDNE	A,[FB%DIR]
	JRST	PGENB2
	RET

PGENB2:	HRROI	B,[ASCIZ/***** directory number zero, but FB%DIR set/]
	JRST	PSTR


padr:	tlne b,10		;must be on for a file address
	 tdne b,[777760,,3]		;and must be divisible by 4
					;and no high-order bits
	  jrst padrx
	ret
padrx:	hrroi b,[asciz/ (Invalid disk address)/]
	jrst pstr

pnam:	movei a,400001		;must be a file name
pnam1:	call chkadr
	 ret			;bad
	hrroi b,1+dpage(b)
	jrst pstr

chkadr:	TLNE	B,-1		;addresses have 0 left halves
	JRST	BADRNG		;out of range
	movei c,dpage(b)
	cail c,dpage		;check for in range
	 camle c,maxloc
	  jrst badrng
	hlrz c,dpage(b)		;get the block type of this thing
	came c,a		;check block type
	 jrst badblk
	aos (p)
	ret
badrng:	hrroi b,[asciz/ *************** address is out of range /]
	jrst pstr
badblk:	hrroi b,[asciz/ **************** points to invalid block type/]
	jrst pstr

pext:	movei a,400002
	jrst pnam1		;?

paut:	movei a,400004
	jrst pact1

;print next FDB
pnfb:	jumpe b,CPOPJ		;no next fdb
	MOVEI	A,400100	;block type of an FDB
	call chkadr
	 ret
	RET

DEFINE	PMSG	(WORD,BIT,MSG)
<	MOVE	A,WORD
	HRROI	B,[ASCIZ\MSG\]
	TDNE	A,[BIT]
	CALL	PSTR
>

PFBCTL:	MOVEM	B,SFBCTL#		;save FBCTL word.
	PMSG	(SFBCTL,FB%DIR,<Directory >)
	PMSG	(SFBCTL,FB%TMP,<Temporary >)
	PMSG	(SFBCTL,FB%PRM,<Permanent >)
	PMSG	(SFBCTL,FB%DEL,<Deleted >)
	PMSG	(SFBCTL,FB%LNG,<Long >)
	RET

pdat:	hrrz a,ojfn
	odtim
	 erjmp .+1
	ret

pact:	movei a,400003
pact1:	call chkadr
	 ret
	hrroi b,2+dpage(b)
	jrst pstr

PFDB:	SETZM	ALOC
PFDB1:	SKIPE	(W)		;is data item zero?
	JRST	PFDB4		;nope.  print something
	MOVE	A,ALOC		;relative location inside FDB
	CAIL	A,FDBTLN	;is it a known location?
	JRST	PFDB3		;no.  suppress zero TYO
	HLRZ	A,FDBFMT(A)	;get the dispatch address
	CAIE	A,CPOPJ
	CAIN	A,PDAT
	JRST	PFDB3		;suppress TYO for zero
PFDB4:	HRROI	B,[ASCIZ/    /]
	CALL	PSTR
	HRRZ	B,ALOC		;print relative locn in FDB
	CALL	PLOC
	HRROI	B,[ASCIZ\/  \]
	CALL	PSTR
	MOVE	A,ALOC		;current location
	CAIL	A,FDBTLN	;special printing?
	JRST	PFDB2		;normal printing
	HRRO	B,FDBFMT(A)	;message for this address
	CALL	PSTR
	MOVE	A,ALOC
	MOVE	B,(W)
	CALL	POCT		;always print octal
	HRROI	B,[ASCIZ/  /]
	CALL	PSTR
	MOVE	A,ALOC		;pseudo loc count
	MOVE	B,(W)		;datum
	HLRZ	A,FDBFMT(A)
	CALL	(A)
	CALL	PCRLF
	JRST	PFDB3

PFDB2:	HRROI	B,[ASCIZ/		/]
	CALL	PSTR
	MOVE	B,(W)
	CALL	POCT
	CALL	PCRLF
PFDB3:	AOS	ALOC
	AOBJN	W,PFDB1
	CALL	PCRLF
	RET

.TYSYM:	CALL	PLOCLW
	HRROI	B,[ASCIZ/Symbol Table/]
	CALL	PSTR
	CALL	PCRLF
	MOVE	B,(W)
	ADDI	W,2
	CAMN	B,(W)
	JRST	.TYSYM		;skip over multiple sym tbl headers
	HRRZ	W,W
TYSYM1:	MOVEM	W,LOC
	CAML	W,MAXLOC
	RET
	MOVE	B,(W)
	CALL	POCT
	MOVEI	B,11
	CALL	PCHR
	MOVE	B,1(W)
	MOVEM	B,NAMBUF
	SETZM	NAMBUF+1
	HRROI	B,NAMBUF
	CALL	PSTR
	CALL	PCRLF
	ADDI	W,2
	JRST	TYSYM1
	subttl iscan

;You may hope to never need this bit of program
;We look at the lost pages file that CHECKD writes.  Take each
;disk address that's found there and check to see if it looks like
;it might be an index page.  If it's an index page, you can guess
;at the name of the file, and reconstruct all the necessary parts
;of an FDB by hand.   Everything considered, it would have been a
;better idea to be on vacation when your disaster happened.

ISCAN:	HRROI	A,[ASCIZ/LOGICAL NAME (ALIAS) OF THIS STRUCTURE   /]
	MOVE	C,A
	PSOUT
	HRROI	A,STRNAM
	MOVEI	B,10
	RDTTY
	 ERJMP	ERCOMM
	MOVE	B,[POINT 7,STRNAM]
ISCL:	MOVE	D,B		;save old pointer
	ILDB	A,B
	CAIE	A,15
	CAIN	A,12
	JRST	ISCL2
	CAIE	A,":"
	JRST	ISCL
ISCL2:	MOVEI	A,0
	DPB	A,B
	HRROI	A,STRNAM
	STDEV
	 ERJMP	ERCOMM
	MOVEM	B,STCODE

	MOVE	A,D		;get pointer
	HRROI	B,[ASCIZ/-LOST-PAGES.BIN/]
	SETZ	C,
	SOUT			;copy string slowly
	
	MOVSI	A,(GJ%OLD!GJ%SHT)
	HRROI	B,STRNAM
	GTJFN
	 ERJMP	ERCOMM
	MOVEM	A,SJFN
	MOVE	B,[440000,,OF%RD]
	OPENF
	 ERJMP	ERCOMM

	HRRZ	A,SJFN
	MOVE	B,[POINT 36,HEADER]
	MOVNI	C,4
	SIN
	 ERJMP	ERCOMM
	HRRZ	A,SJFN
	BIN
	MOVEM	B,ECOUNT
ISCAN1:	HRRZ	A,SJFN
	BIN
	JUMPN	B,ISCAN2
	HRRZ	A,SJFN
	GTSTS
	TLNN	B,(GS%EOF)
	JRST	ISCAN1			;TOSS ZERO
	HRRZ	A,SJFN
	CLOSF
	 ERJMP	ERCOMM
	RET

ISCAN2:	MOVEM	B,ALOC
	CALL	PREAD
	CALL	PSCAN
	JRST	ISCAN1

PREAD:	MOVE	A,ALOC		;DISK ADDRESS
	AND	A,[17,,-1]
	IOR	A,[BYTE(2)2(9)777]
	MOVEI	B,1000
	MOVEI	C,IPAGE
	MOVE	D,STCODE
	DSKOP
	JUMPE	A,CPOPJ
	JRST	ERCOMM


PSCAN:	MOVE	W,[-1000,,IPAGE]
	SETZ	B,
PSC1:	MOVE	A,(W)
	TLNN	A,10		;SKIP IF LIKELY DISK ADDRESS
	JRST	PSCAN2
	TDNE	A,[6,,3]	;SKIP IF NO BAD BITS (2 pack ps?)
	RET
	SETO	B,		;SOMETHING SEEN THAT MIGHT BE GOOD
PSCAN2:	AOBJN	W,PSC1
	JUMPE	B,CPOPJ
	SKIPE	A,IPAGE
	TLNN	A,10
	RET
	HRROI	A,[ASCIZ/LIKELY:  /]
	PSOUT
	MOVEI	A,.PRIOU
	MOVE	B,ALOC
	MOVE	C,[NO%LFL!NO%MAG+<14,,10>]
	NOUT
	 ERJMP	.+1
	HRROI	A,CRLF
	PSOUT
	TRZ	FLAG,F.POCT	;don't dump file contents in octal
	CALL	RDFILE
BR1:	JFCL
	RET
	end start