const string (20) vsn="IMAP12 25 Mar 85" const string (11) rlogfile="REPAIRFLOG" const integer undefined=0, defined=1, selected=2 const integer logstream=28 own integer logstate=undefined const integer no=0, yes= 1 const integer segshift=18 own integer rel lo ind bit; ! leave 12 Epages for BITMAP, NNT etc own integer nnttop own integer rel lo file bit; ! files allocated from here const integer readonly{1}=1, testandreplace{2}=2, amendbplist{4}=4 const integer maxerr=11 const integer {errors from IMAPF}fsys not on line= B'1', {and bits set in } missed users = B'10', {array describing } duplicate users = B'100', {problems } indx pgs in bad list = B'1000', index hdr corrupt = B'10000', should not occur = B'100000', xnnt done = B'1000000', restore from secure = B'10000000', ignore entry = B'100000000', appeared from nowhere= B'1000000000', was in bad plist = B'10000000000', read bitmap etc fail = B'100000000000' const integer array error bits(1:maxerr)= c fsys not on line , missed users , duplicate users , indx pgs in bad list , index hdr corrupt , should not occur , xnnt done , restore from secure , ignore entry , appeared from nowhere, was in bad plist const string (25) array error texts(1:maxerr)= c "fsys not on line ", "missed users ", "duplicate users ", "indx pgs in bad list ", "index hdr corrupt ", "should not occur ", "xnnt done ", "restore from secure ", "ignore entry ", "appeared from nowhere", "was in bad plist " const integer {actions for IMAPF}indexmap=b'1', locateuser = B'10', do bad pages = B'100', empty bad length ks = B'1000' const integer {Actions for TESTSINGLEPAGEFN}readwriterewrite= 1, updatebplist = 2 const string name date=x'80C0003F', time=x'80C0004B' const string (6) not known="NotKnn" !<COMF ! ! This is the Supervisor Communications Record Format, defined in EMAS ! 2900 Supervisor Note 15. ! record format cdrf(byte integer dap no, dap blks, dap process, dap state, integer dap1, dap int) ! record format comf(integer ocptype, ipldev, sblks, sepgs, ndiscs, dlvnaddr, gpctabsize, gpca, sfctabsize, sfca, sfck, dirsite, dcodeda, suplvn, tojday, date0, date1, date2, time0, time1, time2, epagesize, users, cattad, servaad, byte integer nsacs, resv1, sacport1, sacport0, nocps, resv2, ocpport1, ocpport0, integer itint, contypea, gpcconfa, fpcconfa, sfcconfa, blkaddr, ration, smacs, trans, long integer kmon, integer ditaddr, smacpos, supvsn, pstva, secsfrmn, secstocd, sync1dest, sync2dest, asyncdest, maxprocs, kinstrs, elaphead, commsreca, storeaad, procaad, sfcctad, drumtad, tslice, feps, maxcbt, performad, record (cdrf) array cdr(1:2), integer lstl, lstb, pstl, pstb, hkeys, hoot, sim, clkx, clky, clkz, hbit, slaveoff, inhssr, sdr1, sdr2, sdr3, sdr4, sesr, hoffbit, blockzbit, blkshift, blksize, end) ! const record (comf) name com= X'80000000' + 48 << 18 !> !<DISCDATAF ! record format discdataf(integer start, bitsize, nntstart, nntsize, nnttop, nnthash, indexstart, filestart, end) ! ! This format is used in the procedure FBASE2 to return a record giving ! addresses and lengths of the various parts of the disc. ! ! START indicates whether an IPL disc or not, value X40 or X800 ! ! BITSIZE size of the bitmap, X1000, X2000 or X5000 ! ! NNTSTART where the NNT starts ! ! NNTSIZE the size of the name-number table, X1000, X2000 or X4000 ! ! NNTTOP the NNT is a record array declared 0:n, this is n: 340, 681 or 1364 ! ! NNTHASH the largest prime less than NNTTOP, 331, 677 or 1361 ! ! INDEXSTART the total number of pages used for bitmaps and NNTs ! ! FILESTART the number of pages used for bitmaps, NNTs and indexes ! ! END the highest numbered page !> !<FF record format ff(integer sdstart, pdstart, fdstart, sema, reserve1, reserve2, semano, restores, string (6) owner, byte integer size, string (11) name, byte integer fsys, fiphead, tempfiles, eep, integer files, maxfile, maxkb, cherfiles, cherkb, totkb, tempkb, chksum, files0, files1, afiles, atotkb, asema, byte integer attributes, day42) ! only 26 more bytes spare ! PDSTART etc Add to FINDAD to get addr of array ! FILES Number of usable files, ie not 'oldgens' !> !<HH record format hf(string (6) owner, byte integer mark, integer spare1, msgsema, spare2, spare3, inuts, iinstrs, byte integer acr, dirvsn, sigmon, passfails, imax, bmax, tmax, stkkb, iuse, buse, isessm, gpfsys, fsys, sb0, sb1, type, integer top, dwspk, bwspk, binstrs, trying, dinstrs, iptrns, bptrns, imsecs, bmsecs, nkbin, nkbout, mail count, connectt, dirmon, lastlogon, last non int start, tell rej, dwspdt, bwspdt, spare4, spare5, dapsecs, si3, long integer dwsp, bwsp, string (6) gpholdr, string (31) surname, delivery, string (18) batchss, basefile, startf, testss, string (11) logfile, main, string (15) defaultlp, string (63) data, string (6) supervisor, string (15) gateway access id) !> !<NNF ! Note: This program is using the MARKER field of this record in the NNTCopy array record format nnf(string (6) name, byte integer kb, tag, marker, half integer indno) !> !<PARMF ! ! The standard format for system messages record format parmf(integer dest, srce, (integer p1, p2, p3, p4, p5, p6 or string (23) s)) !> own record (nnf) array nnc(0:1364) own record (nnf) array nnt(0:1364) const integer maxprobs=255 record format prof(integer indno, problem, string (6) user) own record (prof) array problem indexes(0:maxprobs) own integer nprobs=0 own integer count= 0 record format pgf(byte integer array pg(0:4095)) external routine spec rstrg(string name s) external routine spec dump(integer start, finish, printst, lim) external routine spec rdint(integer name i) external routine spec prompt(string (15) s) external routine spec clear(string (255) s) external routine spec define(string (255) s) external integer fn spec rdfilead(string (255) s) external routine spec disconnect(string (255) s) external string fn spec itos alias "S#ITOS"(integer i) external string fn spec htos alias "S#HTOS"(integer i, pl) external routine spec phex alias "S#PHEX"(integer i) external string fn spec uinfs(integer i) external integer fn spec uinfi(integer i) external routine spec dout(record (parmf) name p) external routine spec dpon(record (parmf) name p) external integer fn spec testsinglepagefn(integer action, fsys, disc page no, integer name readflag, writeflag, setbpflag) external integer fn spec bad page(integer type, fsys, bitno) external integer fn spec derror(string name txt) external integer fn spec dninda(integer fsys, indno, integer name indad) dynamic integer fn spec dreplaceindex(integer fsys, indno, fromaddr) external integer fn spec dsysad(integer type, adr, fsys) external integer fn spec fbase(integer name lo, hi, integer fsys) external routine spec fill alias "S#FILL"(integer len, from, char) external routine spec get av fsys(integer name n, integer array name a) dynamic integer fn spec dsfi(string (6) user, integer fsys, type, set, adr) external integer fn spec dfstatus(string (31) file index, file, integer fsys, act, value) dynamic integer fn spec dnewuser(string (6) user, integer fsys, nkb) dynamic integer fn spec dnew arch index(string (6) user, integer fsys, kbytes) external routine spec uctranslate alias "S#UCTRANSLATE"(integer adr, len) own record (discdataf) fsys data !------------------------------------------------------------------------ integer fn fbase2(integer fsys, adr) ! This returns the characteristics of an on-line disc in a record ! of format DATAF at address ADR integer j, lob, hib, type, k record (discdataf) name data const integer toptype= 5 const integer array bitsize(1:top type)= X'1000'(2), X'2000'(2), X'5000' const integer array nntstart(1:top type)= X'7000'(4), X'A000' const integer array nntsize(1:top type)= X'4000'(4), X'1FF8' const integer array nnttop(1:top type)= 1364(4), 681 const integer array nnthash(1:top type)= 1361(4), 667 const byte array indexstart(1:top type)= 12(5) const integer array filestart(1:top type)= 1024(5) const integer array hi(1:top type)= X'3F1F', X'59F3', X'8F6F', X'B3E7', X'24797' j=fbase(lob, hib, fsys) result =j unless j=0 type=-1 cycle k=1, 1, top type type=k and exit if hib=hi(k) repeat result =8 if type<0 data==record(adr) data_start=lob data_bitsize=bitsize(type) data_nntstart=nntstart(type) data_nntsize=nntsize(type) data_nnttop=nnttop(type) data_nnthash=nnthash(type) data_indexstart=index start(type) data_filestart=file start(type) data_end=hib result =0 end ; ! FBASE2 ! !------------------------------------------------------------------------ ! routine wrs(string (255) s) printstring(s) newline end ; ! WRS ! !------------------------------------------------------------------------ ! routine wrsn(string (255) s, integer n) printstring(s) write(n, 1) newline end ; ! WRSN ! !------------------------------------------------------------------------ ! routine vvderrs(string (255) s, integer j) string (255) txt return if j=0 j=derror(txt) printstring(s) space wrs(txt) end ; ! VVDERRS ! !------------------------------------------------------------------------ ! routine error integer j string (255) txt j=derror(txt) wrs(txt) end ; ! error ! !------------------------------------------------------------------------ ! routine set rlog noarch integer j j=dfstatus(uinfs(1), rlogfile, uinfi(1), 17, 1) if j#0 start printstring("DFSTATUS fails for ".rlogfile) printstring(" flag ="); write(j, 1) newline finish end {set rlog noarch} integer fn get fsys(integer name fsys) integer j, k, n, online integer array a(0:99) get av fsys(n, a) fsys=-1 while not (0<=fsys<=99) cycle prompt("Fsys: ") rdint(fsys) repeat ! Check that FSYS is in fact online online=0 cycle k=0, 1, n-1 if a(k)=fsys then online=1 and exit repeat if online=0 start ; ! disc not available wrs("Disc not on-line") result =fsys not on line finish j=fbase2(fsys, addr(fsys data)) if j#0 start wrsn("Fundamentally FBASE2 fails ", j) result =j finish result =0 end {get fsys} routine print indno(integer indno, add) printstring("Index no ".itos(indno)."(dec) X".htos(indno, 4)) printstring(" Disc pageno X".htos(fsys data_start+indno>>2, 5)) if add#0 then printstring(" size X".htos(add, 4)) end {print indno} routine narrow dump(integer indad, indno) integer i, k, to, kkk print indno(indno, 0) newline if logstate=selected start printstring("Dump from index position:") newline to=indad+4096 if to>>segshift#indad>>segshift then to=to>>segshift<<segshift {don't go above seg bdy} dump(indad, to, indad, 32) finish else start printstring("Dump of 64 bytes from") printstring(" index position:") newline for i=0, 16, 48 cycle for k=0, 4, 12 cycle for kkk=0, 1, 3 cycle printstring(htos(byteinteger(indad+i+k+kkk), 2)) repeat ! i.e. phex(integer(indad+i+k)) - bypasses unassigned check space repeat newline repeat finish end {narrow dump} routine spec select repair log routine spec select zero routine dee slash(string (23) s) record (parmf) p string (39) s1, s2 s1="Doing a D/".s wrs(s1) p_dest=x'0032000E' p_srce=7 string(addr(p_p1))="D/".s dout(p) s2=string(addr(p_p1)) {The reply} wrs(s2) p_dest=x'320007' p_srce=0 dpon(p); ! UPDATE OPERLOG select repair log wrs(s1) wrs(s2) select zero end ; ! dee slash routine define repair log if logstate#undefined then return define(itos(logstream).",".rlogfile."-MOD") logstate=defined select repair log printstring("**START ".time." ".date) newline printstring("REPAIR FSYS version ".vsn) newline printstring("COM_USERS=".itos(com_users)) newline select zero end {define repair log} routine select repair log integer original logstate original logstate=logstate if logstate=selected then return else if logstate=undefined then define repair log select output(logstream) logstate=selected if original logstate=undefined start printstring("??Initialisation??") newline finish end {select repair log)} routine select zero return if logstate#selected select output(0) logstate=defined end {select zero} routine close repair log integer fad if logstate=undefined then return select repair log printstring("**END ".time) newline select zero close stream(logstream) clear(itos(logstream)) logstate=undefined fad=rdfilead(rlogfile) if fad>0 and integer(fad)>128<<12 start printstring("REPAIRFLOG contains 128Kbytes or more.") newline printstring("Suggest RENAME, DESTROY or ARCHIVE") newline printstring("of same") newline disconnect(rlogfile) finish set rlog noarch end {close repair log} !------------------------------------------------------------------------------- integer fn replace 2k index(integer fsys, indno, fromaddr) integer j, k, indad j=dninda(fsys, indno, indad) if 97#j>0 start for k=1, 1, 2 cycle printstring("DNINDA fails ".itos(j)) newline select repair log repeat select zero result =99 finish select repair log printstring("REPLACE 2K INDEX ") print indno(indno, x'400') newline printstring("Old contents") newline narrow dump(indad, indno) select zero unless fsys data_indexstart<<2<=indno<fsys data_filestart<<2 start printstring("Attempt to ""replace index"" outside index area REJECTED") printstring(" Index number X".htos(indno, 3)) newline j=99 finish else start j=dreplace index(fsys, indno, fromaddr) {replaces 1K of index area} j=j!dreplace index(fsys, indno+1, fromaddr+x'400') if j#0 start for k=1, 1, 2 cycle wrs("DREPLACE INDEX fails ".itos(j)) select repair log repeat select zero result =j finish j=dninda(fsys, indno, indad) if 97#j>0 start for k=1, 1, 2 cycle printstring("DNINDA fails ".itos(j)) newline select repair log repeat select zero result =99 finish for k=0, 4, x'7fc' cycle if integer(indad+k)#integer(fromaddr+k) start printstring("Eeeek!! REPLACE INDEX??? ".htos(k, 4)) newline narrow dump(indad, indno) printstring("--------------------------") narrow dump(fromaddr, indno) exit finish repeat finish result =j end {replace index} !------------------------------------------------------------------------------- routine add problem(string (6) user, integer indno, problem) integer j own integer msg given=0 record (prof) name p j=0 while j<nprobs cycle p==problem indexes(j) if p_user=user and p_indno=indno start p_problem=p_problem!problem return finish j=j+1 repeat if nprobs>=maxprobs start if msg given#0 then return wrs("Too many corrupt/duplicate or missing indexes !!!!") wrs(" Clear and re-prime FSYS ??") msg given=1 return finish p==problem indexes(nprobs) nprobs=nprobs+1 p_user<-user p_indno=indno p_problem=problem end ; ! add problem ! !------------------------------------------------------------------------ ! integer fn index bad(string (6) user) integer j record (prof) name p j=0 while j<nprobs cycle p==problem indexes(j) if p_user=user then result =1 {index bad for USER} j=j+1 repeat result =0 {user not found in BAD list} end ; ! index bad ! !------------------------------------------------------------------------ ! routine recreate index(string (6) user, integer fsys) integer nkb, j, maxkb, maxfile, maxproi, maxprob, maxprot if user="SPOOLR" then nkb=12 else nkb=8 maxfile=x'4000' maxkb=x'8000' maxproi=1; maxprob=1; maxprot=1 j=dnewuser(user, fsys, nkb) vvderrs(user." DNEWUSER", j) return if j#0 j=dnew archindex(user, fsys, 4) vvderrs(user." DNEW ARCH INDEX", j) j=dsfi(user, fsys, 12, 1, addr(maxfile)) vvderrs(user." Set maxfile", j) j=dsfi(user, fsys, 11, 1, addr(maxkb)) vvderrs(user." Set max Kb", j) j=dsfi(user, fsys, 14, 1, addr(maxproi)) vvderrs(user." Set process concurrencies", j) wrs("Create index for ".user." completed") end ; ! recreate index ! !------------------------------------------------------------------------ ! integer fn whos missing(integer fsys) integer pt, flag flag=0 cycle pt=0, 1, nnttop unless length(nnc(pt)_name)<6 start wrs("NNT corruption problem? ") if nnc(pt)_marker#0 wrsn(nnc(pt)_name." missed,FSYS", fsys) wrs("(file index)") if nnc(pt)_tag>0 flag=1 add problem(nnc(pt)_name, nnc(pt)_indno, missed users) finish repeat result =flag end ; ! WHOS MISSING ! !------------------------------------------------------------------------ ! integer fn enter name(string (6) user, string (11) name, integer kb, indno, integer name nntindno) ! ! CHECKS THAT NAME IS IN NNT ! REMOVES ENTRY FROM COPY ! COMMENTS ON AND INSERTS ANY NEW USERS ! RESULT 14 IF NAME ALREADY PRESENT WITH DIFFERENT INDEX ! RESULT = 0 OK ! 1 User appeared from nowhere ! 14 Duplicate integer pt record (nnf) name nn cycle pt=0, 1, nnttop nn==nnt(pt) if user=nn_name start if name="" start {looking for a main index} if nn_tag=0 start {this entry is for a main index} if indno=nn_indno start nnc(pt)_name="" result =0 finish else start nntindno=nn_indno nnc(pt)_marker=1 {to help with the clarity of the reports} result =14 {duplicate} finish finish finish else start if nn_tag>0 start {this entry is for a file index} if indno=nn_indno start nnc(pt)_name="" result =0 finish finish finish finish repeat result =1 end ; ! ENTER NAME ! !------------------------------------------------------------------------ ! integer fn imapf(integer name fsys, string (6) locateu, integer actions) integer j, k, avail pgs, indno, hi, add, done, badp, flag, was bad integer type, pno, errors, problem bits, a neverindex noticed, warn1count integer good, ch, indad, locate flag, lastpno integer readflag, writeflag, setbpflag string (6) user string (11) name record (hf) name h record (ff) name f record (pgf) empty4k routine pcount(integer type, kb) const string (39) array text(1:9)= c {1} "EMPTY 2-Kbyte blocks", {2} "bad character usernames", {3} "duplicate username/NNT entry corrupt", {4} "good indexes", {5} "bad length usernames", {6} "bad size (H_TOP) indexes", {7} "index pge in bad pgs list", {8} "index appeared from nowhere", {9} "good file indexes" const half integer array problem(1:8)= 0, index hdr corrupt {2}, duplicate users {3}, 0, index hdr corrupt(2) {5-6}, indx pgs in bad list {7}, appeared from nowhere {8} string (31) ss ! type: 98765 4321 const integer bad=b'00111101100' own integer prev=-1, prevkb, ino, pno if bad&(1<<type)#0 start errors=1 if type#7 {bad pgs list entry not nec bad} add problem(user, indno, problem(type)) problem bits=problem bits!problem(type) finish if logstate#undefined {i.e. only for REPAIRFSYS} and type#0 and type#1 and type#4 and c type#9 start select repair log print indno(indno, 0) printstring(" ".text(type)) newline select zero finish return if actions&locateuser#0 or actions&indexmap=0 if prev=type and (4#type#9 or kb=prevkb) then count=count+1 else start if prev>0 start printstring("X".htos(ino, 3)) spaces(8) printstring("X".htos(pno, 3)) if bad&(1<<prev)#0 then ss=" **** " else ss=" " printstring(ss) write(count, 4) printstring(" ") ss=text(prev) if count=1 start ch=charno(ss, length(ss)) if ch='s' then length(ss)=length(ss)-1 if substring(ss, length(ss)-1, length(ss))="xe" then length(ss)=length(ss)-1 finish printstring(ss) if prev=3 {duplicate/corrupt NNT indno} start spaces(10) printstring("Indno in NNT = X") printstring(htos(kb, 3)) finish if prev=4 or prev=9 start printstring(" of length") write(prevkb, 2) printstring(" Kbytes") finish newline finish count=1 ino=indno pno=fsys data_start+ino>>2 prevkb=kb if type>0 then prev=type else prev=-1 finish end ; ! PCOUNT ! !-------------------------------- body of fn IMAPF ----------------------------- ! a neverindex noticed=no warn1count=0 fill(1024, addr(empty4k), 0) string(addr(empty4k))="EMPTY" problem bits=0 locate flag=0 rel lo ind bit=fsys data_indexstart nnttop=fsys data_nnttop rel lo file bit=fsys data_filestart if actions&indexmap#0 start ! Start off by test-reading the pages below the start of the indexes proper,namely ! the bit-map, badpages-map, NNT etc. If any of these fail to read, jack out ! to give the option of test-read-writing them using the TESTPAGERANGE program j=0 for pno=fsys data_start, 1, rel lo ind bit-1 cycle j=j!testsinglepagefn(0 {readonly}, fsys, pno, readflag, writeflag, setbpflag) if readflag#0 start printstring("Read fails for pgno X".htos(pno, 5)) newline finish repeat if j#0 start printstring("Consider using the") newline printstring("TESTPAGERANGE progam") newline printstring("to sort these pages") newline result =read bitmap etc fail finish finish errors=0 j=dsysad(1, addr(nnt(0)), fsys) if j#0 start error result =should not occur finish cycle j=0, 1, nnttop nnc(j)=nnt(j) nnc(j)_marker=0 {set one if DUPLICATE remarked} repeat if actions&indexmap#0 start wrs("Index no Disc page no") finish done=0 avail pgs=fsys data_end-fsysdata_start-rel lofilebit indno=rel loindbit<<2-2 hi=rel lo file bit<<2-2; ! last half page lastpno=fsys data_start+rel loindbit-1 add=x'800' until indno>=hi cycle add=x'800' unless add=x'800' or (x'1000'<=add<=x'8000' and add&x'fff'=0) indno=indno+add>>10 ! Set defaults for the following time round user=not known was bad=0 add=x'800'; ! a half page pno=fsys data_start+(indno>>2) if actions&indexmap#0 start ! This next cycle ensures that any pages between lastpno and pno are ! tested, and avoids testing pno more than once (for more than one index ! per page). for j=lastpno+1, 1, pno cycle k=testsinglepagefn(0 {readonly}!updatebplist, fsys, j, readflag, writeflag, setbpflag) if k#0 start printstring("TESTSINGLEPAGE failed") newline printstring("for pageno X".htos(j, 5)) newline finish repeat LASTPNO=PNO finish badp=bad page(3, fsys, pno); ! test: 1=bad, 0=good if badp=yes and actions&do bad pages#0 and indno&3=0 start flag=testsinglepagefn(readwriterewrite!updatebplist, fsys, pno, readflag, writeflag, setbpflag) {Replaces original if poss} select repair log print indno(indno, x'1000') printstring(" was BAD. TESTBADPAGES ") if flag=0 then printstring("succeeded") else printstring("failed") newline select zero if flag=0 start badp=bad page(3, fsys, pno) {Now we hope (indeed expect) it's not in the bad pages list} was bad=1 finish finish if badp=yes start pcount(7, 0) print indno(indno, 0) wrs(" has bit set in bad pages list") add=(4-indno&2)<<10; ! to get to next page continue finish j=dninda(fsys, indno, indad) if 97#j>0 then result =should not occur h==record(indad) if h_owner="NEVER" start if a neverindex noticed=no start wrs("Commencing ""NEVER""-indexes at ") print indno(indno, add) newline a neverindex noticed=yes finish pcount(1, 0) continue finish if a neverindex noticed=yes start if warn1count>16 start wrs("***Thoroughly screwed above ""NEVER""") wrs("***Check abondoned") exit finish wrs("***Something found after ""NEVER"" at ") narrow dump(indad, indno) warn1count=warn1count+1 finish if h_owner="EMPTY" start pcount(1, 0) continue finish good=4 {good index} if length(h_owner)=6 start ! User index user=h_owner name="" type=4 add=h_top finish else start ! File index f==record(indad) unless length(f_owner)=6 and 0<length(f_name)<12 then good=5 {bad length name} user<-f_owner name<-f_name type=9 add=f_size<<9 finish if good=4 {good index} start cycle j=1, 1, 6 ch=charno(user, j) good=2 {bad chs} unless 'A'<=ch<='Z' or '0'<=ch<='9' repeat good=6 {bad size} unless add=x'800' or (x'1000'<=add<=x'8000' and add&X'FFF'=0) ! Does index perchance cross segment boundary? if indad>>segshift#(indad+add-1)>>segshift start wrs("***Index crosses segment boundary !!!") good=6 finish if good#4 {i.e. index not good} start pcount(good, 0) ! If the index WAS in the bad pages list, but is now OK, having ! had a successful TESBADPAGE done, then we must still get rid ! of the index if users have come on the system (unless the ! index got into the bad pages list SINCE the IPL, of course, ! but we have no way of knowing about that), because the user ! would have been MISSED and the space occupied by his files ! could have been re-used. if com_users>2 and was bad#0 then add problem(user, indno, was in bad plist) if actions&indexmap#0 then narrow dump(indad, indno) continue finish if actions&locateuser#0 and user=locateu start locate flag=1 printstring(user) spaces(2) phex(indno) spaces(2) phex(add) if type=9 start printstring(" file index: ") printstring(name) finish newline finish j=enter name(user, name, add>>10, indno, k{for indno from NNT}) if j=0 then pcount(type, add>>10) else start errors=1; ! to include "from nowhere" if j=14 {duplicate} then pcount(3, k) else pcount(8, 0) {appeared from nowhere} finish finish {good=4} else start ! name invalid or something flag=1 if actions&empty bad length ks#0 start flag=replace 2k index(fsys, indno, addr(empty4k)) error unless flag=0 finish good=1 if flag=0 pcount(good, 0) finish repeat errors=errors!whos missing(fsys) pcount(0, 0); ! last count and re-initialise if actions&locateuser#0=locate flag start wrs("Nothing found for ".locateu) finish if errors#0 and actions&indexmap#0 start wrs("****************ERRORS on Fsys ".itos(fsys)."****************") finish result =problem bits end ; ! imapf !------------------------------------------------------------------------------- routine warn printstring("************************************ "); printstring("WARNING. Do not run this program "); printstring("unless you believe you know what "); printstring("you are doing! In particular: do "); printstring("not let a missed index be repaired "); printstring("back to good health, other than by "); printstring("repriming from SECURE, if any FILE "); printstring("HAS BEEN CREATED SINCE CCK. "); printstring("*********************************** "); end {warn} ! !------------------------------------------------------------------------ ! external routine imap(string (255) s) integer i, fsys wrs(vsn) i=get fsys(fsys) return if i#0 i=imapf(fsys, "", indexmap) end ; ! imap !------------------------------------------------------------------------ external routine locateindex(string (255) user) ! This routine should be required only exceptionally. It can be used to locate ! an index for a given username. integer i, fsys wrs(vsn) while length(user)#6 cycle prompt("Give Username to be found: ") rstrg(user) repeat uctranslate(addr(user)+1, 6) i=get fsys(fsys) return if i#0 i=imapf(fsys, user, locateuser) end ; ! locateindex ! !------------------------------------------------------------------------ ! external routine repair fsys(string (255) s) ! This routine reports on, then gets rid of, all indexes and name-number tables ! entries which look peculiar (duplicate, missed, bad header etc.) integer i, j, k, problems, fsys, flag string (6) procowner record (prof) name p, q record (pgf) empty page wrs(vsn) fill(4096, addr(empty page), 0) for j=0, X'800', X'800' cycle string(addr(empty page)+j)="EMPTY" repeat procowner=uinfs(1) if com_users>2 then warn define repair log ! FIRST PASS ! First pass attempts to read and re-write indexes whose page numbers are in the ! bad pages list (and hence to clear them from the bad pages list if the read ! and re-write are successful). i=get fsys(fsys) return if i#0 problems=imapf(fsys, "", do bad pages!indexmap) if problems=read bitmap etc fail then return if {fsys=uinfi(1) %or}index bad(uinfs(1))#0 start for i=0, 1, 7 cycle printch(7) {bel} for j=0, 1, 9 cycle ; printch(0); repeat repeat newline if fsys=uinfi(1) then wrs("Do not REPAIR the FSYS on which you are running !!!") else c wrs("Owner of this program has duplicate index - copy it to another index !!!") finish else start ! SECOND PASS ! If there were any bad pages, or if there were any "duplicate" usernames, we ! go over the fsys again, looking for (more) duplicate/missed. select repair log printstring("Second pass: looking for (any)(more)") newline printstring("duplicate/missed users") if problems&(indx pgs in bad list!duplicate users)#0 start problems=problems!imapf(fsys, "", 0) finish else printstring(" OMITTED (none)") newline select zero ! Meanwhile, the record array PROBLEM USERS has been filled with lots of ! information about the bad indexes. ! Now we get rid of all remaining problem indexes, by writing "EMPTY" in their index ! pages and removing their name-number table entries. j=0 while j<nprobs cycle p==problem indexes(j) if p_user#not known start if p_problem&(missed users!was in bad plist)#0 start dee slash("XNNT ".p_user." ".itos(fsys)) p_problem=p_problem!restore from secure!xnnt done finish if p_problem&appeared from nowhere#0 start p_problem=p_problem!restore from secure finish if p_problem&duplicate users#0 start dee slash("XNNT ".p_user." ".itos(fsys)) if p_problem&xnnt done=0 p_problem=p_problem!xnnt done!restore from secure ! Go to end of list marking entries for same username as 'xnnt done' ! so as not to try to do them a second time (cosmetic) k=j+1 while k<nprobs cycle q==problem indexes(k) if q_user=p_user then q_problem=q_problem!xnnt done!ignore entry k=k+1 repeat finish finish if p_problem&indx pgs in bad list=0 start {only if not (still) marked as "bad"} flag=replace 2k index(fsys, p_indno, addr(empty page)) if flag>0 start error finish else start wrs("Index number X".htos(p_indno, 3)." ""EMPTY-ed""") finish finish j=j+1 repeat ! THIRD PASS ! Replacing 1K areas with the EMPTY pattern will have left following adjacent ! areas which also need emptying (number of such areas potentially unknown, as ! we assume we may not know the size of the index which formerly occupied the ! space). So we go through again, to make the consequent "bad length name" areas ! "EMPTY". j=imapf(fsys, "", empty bad length ks) ! Finally, we report on usernames treated/deleted, and re-create VOLUMS/ ! SPOOLR/MAILER indexes if necessary. j=-1 while j<nprobs cycle j=j+1 p==problem indexes(j) continue if p_problem&ignore entry#0 if p_user="SPOOLR" or p_user="VOLUMS" or p_user="MAILER" start recreate index(p_user, fsys) finish else start if p_problem&restore from secure#0=0 start wrs("Restore user ".p_user." from SECURE tape and re-prime files") finish finish repeat for k=1, 1, 2 cycle {once to terminal, once to repair log} printstring("Summary of affected usernames") newline i=0 j=-1 while j<nprobs cycle j=j+1 p==problem indexes(j) if p_problem&ignore entry=0 and length(p_user)=6 start if p_problem&restore from secure#0 then printstring("*") else printstring(" ") printstring(p_user." ") i=i+1 if i>4 then newline and i=0 finish repeat newline printstring("""*""==>Must RECREATE") newline select repair log repeat select zero newlines(2) wrs("REPAIRFSYS completed. Logfile=".procowner.".".rlogfile) if com_users<=2 {DIRECT+MANAGR} start wrs("Now close down and re-IPL (unless more FSYSes are first to be repaired)") finish finish close repair log end ; ! repair fsys ! !------------------------------------------------------------------------ ! const integer show=1, empty=2 routine show or empty(integer sh or em) ! This routine may be used either to inspect odd pages of the index area for a ! given FSYS or to write the 'EMPTY' pattern ditto. It does not do any writing ! which will not be obvious from the wee dumps and 'yes/no' prompts. integer fsys, indad, j, k, base, iad, ch, indno, online, currpage, currno integer pchanged string (255) s byte integer array aa(0:x'A000') routine show page(integer base, indno, msno) integer len, j const string (71) ss1= c "Here are the current contents of the page around the 2-Kbyte boundaries" const string (71) ss2= c "Summary of page just altered" return if base<0 or (msno=2 and pchanged=0) if msno=1 then wrs(ss1) and len=32 else wrs(ss2) and len=16 for j=0, 2, 2 cycle wrs("Index number X".htos(indno>>2<<2+j, 3)) dump(base, base+len, base, 16) newline base=base+x'800' repeat end ; ! SHOW PAGE wrs(vsn) k=get fsys(fsys) return if k#0 if sh or em=empty start wrs("Note: this program will optionally write ""EMPTY""") wrs(" at the specified 2-Kbyte boundary in the index area") finish currpage=-1; currno=0 iad=addr(aa(0)) fill(1024, iad, 0) string(iad)="EMPTY" cycle prompt("Indexno: ") rdint(indno) exit if indno<0 j=dninda(fsys, indno, indad) if j>0 start error continue finish base=indad>>12<<12 if base#currpage start show page(currpage, currno, 2) show page(base, indno, 1) currno=indno pchanged=0 currpage=base finish if sh or em=empty start wrs("Empty the 2-Kbytes ?") prompt("Y/N: ") rstrg(s) ch=charno(s, 1)&(¬32); ! lower to upper case if ch='Y' start j=replace 2k index(fsys, indno, iad) if j>0 start error finish else wrs("Done ") and pchanged=1 finish else wrs("Abandoned") finish wrs("Give -1 to terminate the program") repeat show page(currpage, currno, 2) end ; ! show or empty ! !------------------------------------------------------------------------ ! external routine show index(string (255) s) show or empty(show) end ; ! show index ! !------------------------------------------------------------------------ ! external routine emptyi(string (255) s) show or empty(empty) end ; ! emptyi ! !------------------------------------------------------------------------ ! end of file