From 336bbaa979a7e461d66184cc7bb5040aad63f0dc Mon Sep 17 00:00:00 2001 From: Eric Swenson Date: Fri, 18 Nov 2016 08:14:56 -0800 Subject: [PATCH] Added channa and dragon directories, and added sources for netime, dmpcpy, fsdefs, modems, netwrk, and pft. --- src/channa/-read-.-this- | 8 + src/channa/logout.times | 1 + src/dragon/dragon.hoard | 119 ++ src/dragon/empty.hoard | 118 ++ src/sysen1/netime.127 | 644 +++++++ src/syseng/dmpcpy.11 | 153 ++ src/syseng/fsdefs.40 | 154 ++ src/syseng/modems.20 | 96 + src/syseng/netwrk.266 | 2705 ++++++++++++++++++++++++++++ src/syseng/pft.149 | 3678 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 7676 insertions(+) create mode 100755 src/channa/-read-.-this- create mode 100755 src/channa/logout.times create mode 100755 src/dragon/dragon.hoard create mode 100755 src/dragon/empty.hoard create mode 100755 src/sysen1/netime.127 create mode 100755 src/syseng/dmpcpy.11 create mode 100755 src/syseng/fsdefs.40 create mode 100755 src/syseng/modems.20 create mode 100755 src/syseng/netwrk.266 create mode 100755 src/syseng/pft.149 diff --git a/src/channa/-read-.-this- b/src/channa/-read-.-this- new file mode 100755 index 00000000..d93069fd --- /dev/null +++ b/src/channa/-read-.-this- @@ -0,0 +1,8 @@ + This directory is used by ITS for startup of +various system programs; RAKASH * files are programs +which, on system startup, ATSIGN TARAKA will load as +system demons... NAMPIC * are files which the NAME +demon uses for picture displays. + + -- The Binders + \ No newline at end of file diff --git a/src/channa/logout.times b/src/channa/logout.times new file mode 100755 index 00000000..7b19b38e --- /dev/null +++ b/src/channa/logout.times @@ -0,0 +1 @@ +ALAN 01/23/57 10:10:10 diff --git a/src/dragon/dragon.hoard b/src/dragon/dragon.hoard new file mode 100755 index 00000000..42aa530a --- /dev/null +++ b/src/dragon/dragon.hoard @@ -0,0 +1,119 @@ + DB Accounting File + + NOT FOR EDITING BY ORDINARY MORTALS + + ~~~~~~~~~~~~ Daemons ~~~~~~~~~~~~ + + User Connect Run Time Swaps Logout + +SYS JOB=SYS +CORE JOB=JOB +COMSAT +TARAKA +PFTHMG JOB=BDAY +PFTHMG JOB=DRAGON +PFTHMG JOB=* +.CHAT. JOB=DEMON + +###A## JOB=ARPA +###A## JOB=* + +###C## JOB=CHAOS +###C## JOB=FILE +###C## JOB=* + +###F## JOB=FTP +###F## JOB=NETRFC +###F## JOB=* + +###K## JOB=CHAOS +###K## JOB=FILE +###K## JOB=* + +###M## JOB=CHAOS +###M## JOB=TCP +###T## JOB=TCP +##TLNT JOB=TELSER +##TLNU JOB=TELSER + +-------------------------- PAGE SUBTOTALS -------------------------- +TOTALS + + + ~~~~~~~~~~~~ Not-logged-in Jobs ~~~~~~~~~~~~ + + User Connect Run Time Swaps Logout + +___### +GUEST +LOGIN + +-------------------------- PAGE SUBTOTALS -------------------------- +TOTALS + + + ~~~~~~~~~~~~ System Hackers ~~~~~~~~~ + + User Connect Run Time Swaps Logout + +ALAN +ALAN5 +BAWDEN +CBF +CENT +CENT5 +CHRIS +CSTACY +DCP +DEC +DIGEX +DPH +ECC +GREN +GSB +GSB5 +GZ +JINX +JNC +JPG +JTW +KLH +MOON +MOON5 +OAF +RDZ +ROLL +SRA +TAFT +TK + +-------------------------- PAGE SUBTOTALS -------------------------- +TOTALS + + +----------------------------- RANDOMS ----------------------------- + + User Connect Run Time Swaps Logout + +-------------------------- PAGE SUBTOTALS -------------------------- +TOTALS + + +------------------------------ TOTALS ------------------------------ +TOTALS + + + STATS fups crfts core runt + +STATS 0 0 0 0.0 + + FUPS - # of file updates + CRFTYS - # of pieces of cruft pushed from logouts + CORE - # of times core has been grown. Core is flushed when file updated. + RUNT - runtime consumed by PFTHMG + + This file is for period beginning 88.12.28 00:00:00 + + System Uptime Report + +OK 88.12.28 00:00:00 0 diff --git a/src/dragon/empty.hoard b/src/dragon/empty.hoard new file mode 100755 index 00000000..1802c602 --- /dev/null +++ b/src/dragon/empty.hoard @@ -0,0 +1,118 @@ + ZZ Accounting File + + NOT FOR EDITING BY ORDINARY MORTALS + + ~~~~~~~~~~~~ Daemons ~~~~~~~~~~~~ + + User Connect Run Time Swaps Logout + +SYS JOB=SYS +CORE JOB=JOB +COMSAT +TARAKA +PFTHMG JOB=BDAY +PFTHMG JOB=DRAGON +PFTHMG JOB=* +.CHAT. JOB=DEMON + +###A## JOB=ARPA +###A## JOB=* + +###C## JOB=CHAOS +###C## JOB=FILE +###C## JOB=* + +###F## JOB=FTP +###F## JOB=NETRFC +###F## JOB=* + +###K## JOB=CHAOS +###K## JOB=FILE +###K## JOB=* + +###M## JOB=CHAOS +###M## JOB=TCP +###T## JOB=TCP +##TLNT JOB=TELSER +##TLNU JOB=TELSER + +-------------------------- PAGE SUBTOTALS -------------------------- +TOTALS + + + ~~~~~~~~~~~~ Not-logged-in Jobs ~~~~~~~~~~~~ + + User Connect Run Time Swaps Logout + +___### +GUEST +LOGIN + +-------------------------- PAGE SUBTOTALS -------------------------- +TOTALS + + + ~~~~~~~~~~~~ System Hackers ~~~~~~~~~ + + User Connect Run Time Swaps Logout + +ALAN +ALAN5 +BAWDEN +CBF +CENT +CENT5 +CHRIS +CSTACY +DCP +DEC +DPH +ECC +GREN +GSB +GSB5 +GZ +JINX +JNC +JPG +JTW +KLH +MOON +MOON5 +OAF +RDZ +ROLL +SRA +TAFT +TK + +-------------------------- PAGE SUBTOTALS -------------------------- +TOTALS + + +----------------------------- RANDOMS ----------------------------- + + User Connect Run Time Swaps Logout + +-------------------------- PAGE SUBTOTALS -------------------------- +TOTALS + + +------------------------------ TOTALS ------------------------------ +TOTALS + + + STATS fups crfts core runt + +STATS 0 0 0 0.0 + + FUPS - # of file updates + CRFTYS - # of pieces of cruft pushed from logouts + CORE - # of times core has been grown. Core is flushed when file updated. + RUNT - runtime consumed by PFTHMG + + This file is for period beginning YY.MM.DD 00:00:00 + + System Uptime Report + +OK YY.MM.DD 00:00:00 0 diff --git a/src/sysen1/netime.127 b/src/sysen1/netime.127 new file mode 100755 index 00000000..7e3a699c --- /dev/null +++ b/src/sysen1/netime.127 @@ -0,0 +1,644 @@ +; -*- Midas -*- + +title NETIME - Get the time from the network. + +rdtim=:702200,, ; KS10 clock instructions. +wrtim=:702600,, +clk==:500 ; PD clock on KA10s and MX-KL + +a=:1 +b=:2 +c=:3 +d=:4 +e=:5 +t=:6 +tt=:7 + +p=:17 + +ttyoch==:1 +netoch==:2 +nnetch==:<20-netoch>/2 +netich==:netoch+nnetch +utilch==:2 + +call=:pushj p, +return=:popj p, +save==:push p, +rest==:pop p, +flose=:.lose %lsfil +slose=:.lose %lssys +pause=:.break 16,100000 +quit=:.logout 1, +tyo=:.iot ttyoch, + +define conc foo,bar +foo!bar!termin + +%f==:1,,525252 ; Flags in LH(0) +%fhsts==:000002 ; Host table loaded? +%ftime==:000004 ; Timer + +repeat nnetch, conc %fnet,\.rpcnt,==:1_ + +netmsk==:<1_nnetch-1>_netich + +define syscall name,args + .call [setz ? sixbit /name/ ? args(400000)] +termin + +popbj1: rest b +popj1: aosa (p) +popbj: rest b +cpopj: return + +datime"$$svng==:1 +datime"$$out==:1 +datime"$$abs==:1 +.insrt dsk:syseng;datime > + +format"$$time==:1 +format"datime==:datime"twdasc +format"time==:datime"timasc +format"date==:datime"datasc +format"$$pcode==:1 +.insrt dsk:syseng;format > + +outstr: syscall siot,[movei ttyoch ? a ? b] + slose + return + +define format &string&,args + call [ + call $format +.zzz.==-1 +irp arg,,[args] + save arg +.zzz.==.irpcnt +termin + hrroi a,[ascii string] + movei b,.length string + movni c,.zzz.+1 + jrst format"format] +termin + +$forma: save a + save b + save c + save [.+2] + jrst @-4(p) + rest c + rest b + rest a + rest (p) + return + +; Hosts are arranged first into three groups by approximate speed and +; reliability. Each group is in alphabetical order. Presumably there is +; little correlation between a machine's speed and reliability, and the +; alphabetical position of its name. + +hosts: + +; Ask the reliable ITS machines first. They are all on subnet 6 and tend +; to answer quickly. + + <(sixbit /AI/)>,,[asciz "AI"] + <(sixbit /MC/)>,,[asciz "MC"] + <(sixbit /ML/)>,,[asciz "ML"] + +; File servers tend to be up. Approximately in the order that they seem +; likely to come up after a mass shutdown. + + [asciz "REAGAN"] + [asciz "ZERMATT"] + [asciz "GOLDILOCKS"] + [asciz "LIVE-OAK"] + [asciz "PYGMALION"] + [asciz "HEPHAESTUS"] + +; Ordinary hosts. Alphabetical order. + + [asciz "BIGBOOTE"] + [asciz "CROSBY"] + [asciz "DIALUP-CHAOS"] + [asciz "GAAK"] + [asciz "MINTAKA"] + [asciz "OTIS"] + [asciz "PIGPEN"] + [asciz "SAFFRON"] + [asciz "SINATRA"] + +; Unreliable hosts start here. Putting hosts that tend to not answer at +; the end keeps them from acting as a bottleneck. (It also gives them less +; time to respond...) + + <(sixbit /MD/)>,,[asciz "MD"] + [asciz "GOLEM"] + [asciz "LSD"] + [asciz "EMACK-AND-BOLIOS"] + +nhosts==:.-hosts + +;;; Parameters that can be patched: + +setp: -1 ; 0 => don't actually set the time. + +wait: 20.*60. ; Wait 20 seconds polling other hosts. + 0 ? 0 ? 0 ; Zeros for .REALT just in case... + +numerq: 2 ; Ceiling of 2/3 of the hosts that respond +denomq: 3 ; must agree on the time. + +minq: 4 ; Insist on at least 4 hosts with times in + ; agreement. + +spread: 400. ; Times agree if they differ by less than + ; 400 seconds (6 mins 40 secs) + +days: 3 ; If machine looks like it was down for + ; this many days, then require a human to + ; set the time. + +filesn: sixbit /DRAGON/ ; The creation date of this file is some +filen1: sixbit /DRAGON/ ; indication of what time the system last +filen2: sixbit /HOARD/ ; thought it was. + +.scalar lstime ; Creation date of above file. + +.insrt dsk:system;chsdef > +.vector opkt(%cpmxw) ; Output packet +.vector ipkt(%cpmxw) ; Input packet + +.vector state(nnetch) ; What each net channel is working on. + +.vector times(nhosts) ; The time reported by each host. + ; In seconds since January 1, 1900, GMT. + +.vector atimes(nhosts) ; The time we believe the host looked at + ; his clock. In 60ths of a second since + ; system was booted. + +.scalar count ; The number of outstanding time requests. + +lpdl==:100. +.vector pdl(lpdl) ; The usual. + +.scalar itsnam ; The name of this machine in SIXBIT. + +usrvar: sixbit /OPTION/ ? tlo %opint\%opopc + sixbit /MASK/ ? move [%pirlt\%piioc\%piwro\%pimpv\%pilos\%piilo] + sixbit /MSK2/ ? movei netmsk +lusrvar==:.-usrvar + +go: .pdtime b, + .suset [.rsuppro,,a] + came b,[-1] + jumpl a,[quit] + movsi b,(sixbit /T00/) + skipl a + movsi b,(sixbit /TTY/) + syscall open,[[.uao\%tjdis,,ttyoch] ? b] + skipa + jrst go1 + movei tt,5*30. + .sleep tt, + jrst go + +go1: move tt,[%rlfls\%rlset,,wait] + .realt tt, + movsi 0,netmsk ; initial flags + move p,[-lpdl,,pdl-1] + move tt,[-lusrvar,,usrvar] + syscall usrvar,[movei %jself ? tt] + slose + syscall sstatu,[repeat 6,[ ? movem itsnam]] + slose + syscall open,[[.uai\%donrf,,utilch] ? [sixbit /DSK/] + filen1 ? filen2 ? filesn] + jrst nofile + syscall rfdate,[movei utilch ? movem lstime] + flose + .close utilch, +irps sym,,[ka10p,kl10p,ks10p,pdtime,fyear] +.scalar sym + move tt,[squoze 0,sym] + .eval tt, + .lose + movem tt,sym +termin + move tt,[squoze 0,ksfreq] + .eval tt, + movei tt,<<1000._12.>+30.>/60. + movem tt,ksfreq + + movei a,netgo + movem a,state+0 + move tt,[state+0,,state+1] + blt tt,state+nnetch-1 + setzm times+0 + move tt,[times+0,,times+1] + blt tt,times+nhosts-1 + movei a,%corfc + dpb a,[$cpkop opkt] + movei a,4 + dpb a,[$cpknb opkt] + move a,[.byte 8 ? "T ? "I ? "M ? "E] + movem a,opkt+%cpkdt + setzm count + hrloi c,-1-nhosts ; C: aobjn into hosts +loop: tlnn netmsk\%ftime + .hang + tlze %ftime + jrst timout + jffo .+1 + movei b,17.-netich + sub b,a ; B: current net channel + move t,state(b) + hlrz d,t ; D: usually current host + jrst (t) + +tsint: +loc 42 + -ltsint,,tsint +loc tsint + 0,,p + %piioc ? 0 ? 0 ? 0 ? iocint ; synchronous + %pirlt ? 0 ? 0 ? 0 ? timint + 0 ? netmsk ? 0 ? 0 ? netint + %piwro\%pimpv\%pilos\%piilo ? 0 ? -1 ? -1 ? badint +ltsint==:.-tsint + +dismis: setz ? sixbit /DISMIS/ ? setz p + +badint: .close ttyoch, ; Close TTY channel to let hacker log in + .value ; Leave a corpse + +netint: tso -3(p) + .call dismis + slose + +timint: tlo %ftime + .call dismis + slose + +iocint: save t + aos -1(p) + hrrz t,-1(p) + caie t,iocok+1 + .lose + rest t + .call dismis + slose + +netgo: aobjp c,nomore + hllz a,hosts(c) + camn a,itsnam ; Is this us? + jrst netgo + hrrz a,hosts(c) + call look + jrst netgo ; Must be gone or something? + dpb a,[$cpkda opkt] + syscall chaoso,[movei netich(b) ? movei netoch(b)] + jrst netgo ; Chaosnet full? Broken? + tdz netbit(b) + syscall pktiot,[movei netoch(b) ? movei opkt] + slose + .rdtime tt, + movem tt,atimes(c) ; Begin our wait + hrrzi a,netin + hrli a,(c) + movem a,state(b) + aos count + jrst loop + +netin: sos count +iocok:: syscall pktiot,[movei netich(b) ? movei ipkt] + jrst netgo ; IOC ints return to here. + .rdtime tt, + addm tt,atimes(d) ; End our wait (computes average in 60ths) + ldb t,[$cpkop ipkt] + caie t,%coans + jrst netgo + ldb t,[341000,,ipkt+%cpkdt] + dpb t,[001000,,times(d)] + ldb t,[241000,,ipkt+%cpkdt] + dpb t,[101000,,times(d)] + ldb t,[141000,,ipkt+%cpkdt] + dpb t,[201000,,times(d)] + ldb t,[041000,,ipkt+%cpkdt] + dpb t,[301000,,times(d)] + jrst netgo + +netbit: repeat nnetch, 1_,,0 + +nomore: syscall close,[movei netich(b)] + slose + syscall close,[movei netoch(b)] + slose + tdz netbit(b) + movei a,[ jfcl ? .lose ] + movem a,state(b) + skipe count + jrst loop + jrst setime + +.vector sorted(nhosts) ; Sorted indices of times. + +timout:: +setime: skipn setp + jrst sort + setoi tt, + .iotlsr tt, + ;; Set time relative to -now-. + skipe ks10p + rdtim kstime + skipn ks10p + datai clk,clktim +sort: .rdtime e, + lsh e,1 ; E: system time in 60ths + addi e,30. ; (for rounding later) + setzi b, ; B: # entries sorted so far + movsi a,-nhosts ; A: aobjn into TIMES + skipn c,times(a) ; C: time +sortlp: aobjn a,.-1 ; Skip people who didn't answer + jumpge a,vote + move t,e ; Compute time since he looked at his clock + sub t,atimes(a) + idivi t,60. ; Convert to seconds (rounded) + add c,t + movem c,times(a) + skipn d,b ; D: candidate index for insertion + jrst sort0 +sort1: move tt,sorted-1(d) + camge c,times(tt) + sojg d,sort1 +sort0: movei tt,(d) + subi tt,1(b) + hrli d,(tt) ; D: aobjn into part or SORTED to move + movei tt,(a) ; The index to insert + exch tt,sorted(d) + aobjn d,.-1 + aoja b,sortlp + +.scalar ntimes ; The number of people who responded. +.scalar quorum ; The size of a quorum + +vote: movem b,ntimes + imul b,numerq + add b,denomq + soj b, + idiv b,denomq + camge b,minq + move b,minq + movem b,quorum + setzi a,0 ; A: index of possible lowest good time + soj b, ; B: must agree with A for quorum +low: caml b,ntimes + jrst nogo + move tt,sorted(b) + move t,times(tt) + move tt,sorted(a) + sub t,times(tt) + camg t,spread + jrst gotlow + aoj a, + aoja b,low + +gotlow: move b,ntimes + movei c,-1(b) ; C: index of possible highest good time + sub b,quorum ; B: must agree with C for quorum +high: move tt,sorted(c) + move t,times(tt) + move tt,sorted(b) + sub t,times(tt) + camg t,spread + jrst gotime + soj b, + soja c,high + +.scalar lowest ; Index of lowest of good times. +.scalar highest ; Index of highest of good times. +.scalar median ; Index of median of good times. +.scalar host ; Pointer to ASCIZ name of winning host. +.scalar time ; Winning network time. +.scalar qtime ; Winning network time in disk format. +.scalar qzone ; SIXBIT timezone of QTIME. +.scalar year ; Year of winner. +.scalar ticks ; PD-ticks since January 1 of winner. +.scalar ksfreq ; KS-tick per PD-tick +.vector kstime(2) ; Set time relative to this. +.scalar clktim ; Or this. + +s%d==:24.*60.*60. +s%y==:365.*s%d +s%est==:datime"estdif*60.*60. +gotime: movem a,lowest + movem c,highest + addi c,1(a) + lsh c,-1 + movem c,median + move tt,sorted(c) + hrro a,hosts(tt) + movem a,host + move a,times(tt) + movem a,time + call cvtime + movem e,qzone + movem a,qtime + move b,lstime + call datime"timsub + add a,spread ; Allow for the usual fuzz... + jumpl a,past + move tt,days + imuli tt,s%d + camle a,tt + jrst future + ldb b,[.bp datime"tm%yr,qtime] ; EST and EDT always agree about + movei tt,1900.(b) ; the year! + movem tt,year + subi b,1 ; (Compensates for the fact that 1900. was + idivi b,4 ; not a leap year. (Screws up if you give + addi c,1 ; a time in 1900., but who cares?)) + imul b,[4*s%y+s%d] + imul c,[s%y] + add b,c ; B: Seconds from 1/1/00 to this year. + move a,time + subi a,s%est ; GMT -> EST + sub a,b + imuli a,60. + movem a,ticks + skipn setp + jrst nsetp + + skipn ks10p + jrst notks + dmove a,kstime + hrrz a,a ; Clear possible gubbish from high bits. + div a,ksfreq ; KS-ticks -> PD-ticks + jrst doit + +notks: move a,clktim + tlz a,600000 ; Clear possible gubbish from high bits. + ;; On a KA if this is zero then apparently the PD clock is off. + ;; Fix this code to deal with that if you try to bring this code up + ;; on a KA (see PDSET program). (Where did you find a working ITS + ;; KA10 anyway?) + skipe ka10p + .lose +doit: sub a,ticks ; A: offset for loading into PDTIME + format "~&Setting the time to be ~Q ~S ~ + (supplied by ~A).~&",[qtime,qzone,host] + move tt,fyear + hrli tt,year + .setloc tt, + move tt,pdtime + hrli tt,a + .setloc tt, + skipa ; This is supposed to give the SETLOC + skipa ; a chance to happen before starting the + .hang ; clock. + setoi tt, + .iotlsr tt, + skipe kl10p + cono clk,400007 ; Start clock on KL + skipn ks10p + quit + rdtim t + hrli t,1729. + wrtim t + quit + +nsetp: format "~&Would have set the time to be ~Q ~S (supplied by ~A).~ + ~& FYEAR/ ~D. PDTIME/ ~D.~&",[qtime,qzone,host,year,ticks] + call table + quit + +notset: format " + + Attention! + + Attention! + +The time could not be set because:" + call (a) + format "~&It will be necessary for someone to set the time~@ + manually by logging in and running :PDSET.~2&" + quit + +nofile: jsp a,notset + format "~&There was an error accessing the file ~ + ~S;~S ~S.",[filesn,filen1,filen2] + return + +bogus: format "~&The best time, ~Q ~S (supplied by ~A),",[qtime,qzone,host] + call (a) + format "~Q, the creation date of ~ + ~S;~S ~S.",[lstime,filesn,filen1,filen2] + return + +future: jsp a,notset + jsp a,bogus + format " was more than~&~D day~P beyond ",[days] + return + +past: jsp a,notset + jsp a,bogus + format " was~&prior to " + return + +nogo: jsp a,notset + skipn t,ntimes + jrst nogo0 + camge t,quorum + jrst nogo1 + format "~&Of the ~D answer~P recieved, ~ + no ~D agreed to within ~D seconds.",[ntimes,quorum,spread] + return + +nogo0: format "~&No host responded." + return + +nogo1: format "~&Only ~D host~P responded.",ntimes + return + +;;; CALL TABLE: Print a table of everything we know. +table: save a + save b + save e + format "~&~D host~P responded.",ntimes + skipe count + format " ~D outstanding request~P.",count + movei b,0 +tablel: caml b,ntimes + jrst tablex + move tt,sorted(b) + move a,times(tt) + call cvtime + move tt,sorted(b) + hrro t,hosts(tt) + format "~&~3<~D~>: ~Q ~S ~A",[b,a,e,t] + aoja b,tablel + +tablex: format "~&Low=~D High=~D Median=~D",[lowest,highest,median] + format "~&Quorum=~D Spread=~D sec.~&",[quorum,spread] + rest e + rest b + rest a + return + +;;; CALL CVTIME: Convert network time to local disk format time word. +;;; A (arg): network time +;;; A (val): disk format date +;;; E (val): SIXBIT of timezone +cvtime: subi a,s%est ; GMT -> EST + call datime"sectim ; -> disk format date + save b + movei b,60.*60. + call datime"odayl + skipa e,[sixbit /EDT/] + skipa e,[sixbit /EST/] + call datime"timadd + rest b + return + +netwrk"$$hstmap==:1 +netwrk"$$hostnm==:1 +netwrk"$$symlook==:1 +netwrk"$$chaos==:1 +.insrt dsk:syseng;netwrk > + +;;; CALL LOOK: Look up the Chaosnet address of a host. +;;; A (arg): address of ASCIZ string +;;; A (val): host number +;;; Skips if the host is found. +look: save b + tloe %fhsts + jrst look1 + save a + movei a,ffpage + movei b,utilch + .iopush utilch, + call netwrk"hstmap + .lose + .iopop utilch, + rest a +look1: call netwrk"hstlook + jrst popbj + rest b + aos (p) + return + +cnstnts: +constants + +patch:: +pat: block 100. + +variables + +ffaddr: -1 ; Make memory exist + +ffpage==:_-12 + +end go diff --git a/src/syseng/dmpcpy.11 b/src/syseng/dmpcpy.11 new file mode 100755 index 00000000..a099bb6e --- /dev/null +++ b/src/syseng/dmpcpy.11 @@ -0,0 +1,153 @@ +; -*- MIDAS -*- + + TITLE DMPCPY - COPY DUMPS FROM SWAP AREA TO FILE AREA + +A=1 +B=2 +C=3 +D=4 +E=5 +T=6 +TT=7 +P=17 + +CHDIRI=10 +CHDSKI=11 +CHDSKO=12 + +.INSRT SYSENG;FSDEFS > + +PDL: -20,,. + BLOCK 20 + +;DIRECTORIES WHERE STUFF MIGHT GET DUMPED OUT OF TIMESHARING +DIRLST: SIXBIT/./ + SIXBIT/CRASH/ + SIXBIT/CRASH2/ +NDIRS==.-DIRLST + +DIR: BLOCK 2000 +BUF: BLOCK 2000 + +USRVAR: SIXBIT /OPTION/ ? TLO %OPINT\%OPOPC + SIXBIT /MASK/ ? MOVE [%PIIOC\%PIPDL] +LUSRVAR==:.-USRVAR + +GO: .CLOSE 1, ;RUNS AS DAEMON + MOVE P,PDL + MOVE TT,[-LUSRVAR,,USRVAR] + .CALL [ SETZ ? SIXBIT /USRVAR/ + MOVEI %JSELF + SETZ TT ] + .LOSE %LSSYS +CHKTIM: .CALL [ SETZ ? SIXBIT /RQDATE/ ; don't frob with files + SETZM A ] ; if system doesn't know the time + .LOSE %LSSYS + AOJN A,KNOTIM + MOVEI A,30.*15. ; 15 seconds + .SLEEP A, + JRST CHKTIM + +KNOTIM: MOVSI E,-NDIRS +CHKDIR: .CALL [ SETZ ? SIXBIT/OPEN/ + [.BII,,CHDIRI] + [SIXBIT/DSK/] + [SIXBIT/.FILE./] + [SIXBIT/(DIR)/] + SETZ DIRLST(E)] + JRST NXTDIR ; Hey, there might not -be- such a directory! + MOVE TT,[-2000,,DIR] + .IOT CHDIRI,TT + .CLOSE CHDIRI, + MOVE D,UDNAMP+DIR +CHKFIL: CAIL D,2000 + JRST NXTDIR + MOVE TT,UNRNDM+DIR(D) + SKIPGE UNDATE+DIR(D) + TLNE TT,UNDUMP\UNIGFL\UNREAP\UNLINK ; Don't screw with files + JRST NXTFIL ; you don't understand. + ;HERE WE HAVE FOUND A FILE WRITTEN OUT OF TIMESHARING + ;COPY IT SO AS TO (1) SET THE FILE DATE AND (2) GET IT OUT + ; OF THE SWAPPING AREA. NTS FILES ARE WRITTEN IN THE SWAPPING + ; AREA TO DECREASE THE PROBABILITY OF CLOBBERING SOME OTHER FILE. + .CALL [ SETZ ? SIXBIT/OPEN/ + MOVES TT + [.BII,,CHDSKI] + [SIXBIT/DSK/] + UNFN1+DIR(D) + UNFN2+DIR(D) + SETZ DIRLST(E) ] + JSP T,[ CAIE TT,%ENSFL ; perhaps a hacker deleted it + CAIN TT,%ENAPK ; perhaps that pack had to go offline + JRST NXTFIL + JRST LOSE ] + .CALL [ SETZ ? SIXBIT/OPEN/ + MOVES TT + [.BIO,,CHDSKO] + [SIXBIT/DSK/] + [SIXBIT/_DMPCP/] + [SIXBIT/OUTPUT/] + SETZ DIRLST(E) ] + JSP T,[ CAIE TT,%EFLDR + JRST LOSE + MOVEI TT,30.*60.*5 ; 5 minutes + .SLEEP TT, + JRST .-1 ] +CPYFIL: MOVE TT,[-2000,,BUF] + .IOT CHDSKI,TT + MOVEI T,-BUF(TT) + JUMPE T,ENDFIL + MOVNS T + MOVSS T + HRRI T,BUF + .IOT CHDSKO,T + JRST CPYFIL + +ENDFIL: .CLOSE CHDSKI, + .CALL [ SETZ ? 'RENMWO + MOVEI CHDSKO + UNFN1+DIR(D) + SETZ UNFN2+DIR(D) ] + .LOSE %LSSYS + .CLOSE CHDSKO, +NXTFIL: ADDI D,LUNBLK + JRST CHKFIL + +NXTDIR: AOBJN E,CHKDIR + .LOGOUT 1, + .VALUE + +; JSP T,LOSE is like .LOSE %LSFIL(TT) +LOSE: .CALL [ SETZ ? SIXBIT /LOSE/ + MOVEI %LSFIL(TT) + SETZI -2(T) ] + .LOSE %LSSYS + +TSINT: +LOC 42 + -LTSINT,,TSINT +LOC TSINT + P + %PIIOC ? 0 ? %PIIOC ? 0 ? IOCINT +LTSINT==:.-TSINT + +; If there is a disk or directory full problem, wait for someone to notice. +IOCINT: PUSH P,T + .SUSET [.RBCHN,,T] + CAIE T,CHDSKO + .LOSE + .STATUS CHDSKO,T + LDB T,[330500,,T] + CAIE T,11 ; DEVICE FULL + CAIN T,14 ; DIRECTORY FULL + JRST WAIT + .VALUE + +WAIT: MOVEI T,30.*60.*5 ; 5 minutes + .SLEEP T, + POP P,T + .CALL [ SETZ ? SIXBIT /DISMIS/ + SETZ P ] + .LOSE %LSSYS + +END GO diff --git a/src/syseng/fsdefs.40 b/src/syseng/fsdefs.40 new file mode 100755 index 00000000..af11b33b --- /dev/null +++ b/src/syseng/fsdefs.40 @@ -0,0 +1,154 @@ +.AUXIL + +IFNDEF DEFSYM,[ ;ALLOW USER TO USE SYMBOLS IN OTHER WAYS IF HE WISHES. + ;BUT NORMALLY, DEFSYM FOO==BAR DOES FOO==BAR WITH ERROR CHECK. +DEFINE DEFSYM X/ +IRPS Z,,[X] +IFNDEF Z,X +.ELSE [ + $$TEM1==Z + X + IFN Z-$$TEM1,.ERR Z MULTIPLY .QUOTE`.QUOTE/DEFINED/` +] +.ISTOP +TERMIN TERMIN + +IFLE .MLLIT,.ERR .MLLIT MUST BE 1; SETTING IT TO 1. +.MLLIT==1 +$$TEMP==1 +] +.ELSE $$TEMP==0 + +;FILE SYSTEM PARAMETERS - APPLIES TO ALL ITS MACHINES + +;9/5/79 - tut format changed! + +;MFD INFO + +IFDEF NBLKS,[ ;MFDBLK KNOWN ONLY IF .INSRT APPROPRIATE PHYSICAL PARAMS FILE +DEFSYM MFDBLK==NBLKS/2-1 ;LOC ON DISK +DEFSYM MFDCYL==MFDBLK/NBLKSC +DEFSYM MFDSRF==*SECBLK/NSECS +DEFSYM MFDSEC==*SECBLK-MFDSRF*NSECS +] + ;RANDOM INFO IN MFD +DEFSYM MDNUM==0 ;ASCENDING DIR NUM +DEFSYM MDNAMP==1 ;PNTR TO ORG OF USER NAME BLOCK AREA +DEFSYM MDYEAR==2 ;CURRENT YEAR +DEFSYM MPDOFF==3 ;DE-CORIOLIS CLOCK OFFSET +DEFSYM MPDWDK==4 ;PREFERRED WRITING DISK (PHYSICAL DRIVE #) +DEFSYM MDCHK==5 ;THIS WORD MUST BE M.F.D. (FOR CHECKING) +DEFSYM MDNUDS==6 ;NUMBER USER DIRECTORIES (FOR CHECKING ONLY) +DEFSYM LMIBLK==7 ;TOTAL STG USED BY HACKS LIKE THIS + ;USER NAME BLKS FROM C(MDNAMP) TO END +DEFSYM LMNBLK==2 ;# WDS/BLK +DEFSYM MNUNAM==0 ;6BIT USER NAME + ;SECOND WORD OF A USER-NAME BLOCK IS ZERO. + ;DECUUO CONTAINS A KLUDGE WHICH DEPENDS ON THIS, + ;PLEASE NOTIFY BUG-DECUUO BEFORE CHANGING IT. + +;TUT INFO + +IFDEF NBLKS,[ +DEFSYM TUTBLK==MFDBLK-NTUTBL ;LOC ON DISK +DEFSYM TUTCYL==TUTBLK/NBLKSC +DEFSYM TUTSRF==*SECBLK/NSECS +DEFSYM TUTSEC==*SECBLK-TUTSRF*NSECS +] +DEFSYM TUTBYT==3 ;SIZE OF BYTES (USED TO BE 4) +DEFSYM TUTBP==<440000+TUTBYT_6>,, +DEFSYM TUTEPW==36./TUTBYT ;NUMBER OF ENTRIES PER WORD +DEFSYM TUTMAX==1_TUTBYT +DEFSYM TUTLK==TUTMAX-1 ;HIGHEST CODE MEANS LOCKED OUT +DEFSYM TUTMNY==TUTLK-1 ;TUT MANY OR MORE REFS + +;RANDOM INFO IN TUT (AT THE FRONT) +DEFSYM QPKNUM==0 ;PACK # +DEFSYM QPAKID==1 ;PACK ID +DEFSYM QTUTP==2 ;FREE SPACE POINTER TO TRACK AREA. ADVANCE BY CYLINDERS +DEFSYM QSWAPA==3 ;SWAPPING AREA. FIRST TRACK OF NON-SWAPPING AREA + ;NEW FILES WILL NOT BE WRITTEN LOWER THAN THIS. +DEFSYM QFRSTB==4 ;FIRST BLOCK TUT'ED +DEFSYM QLASTB==5 ;LAST BLOCK TUT'ED +DEFSYM QTRSRV==6 ;-1 IF ONLY ALLOCATED DIRS CAN HAVE FILES ON THIS PACK + ;IF NOT 0 AND NOT -1, SIXBIT NAME OF "SECONDARY" PACK + ;STG FOR RANDOM INFO ^ +DEFSYM LTIBLK==20 ;BYTES MAPPING THE DISK START HERE + +;UFD INFO +;IF A IS RELATIVE LOCATION OF MFD ENTRY, USER DIR IS LOCATED IN +;TRACK NUMBERED /2 (SEE QFL2) + +DEFSYM UFDBYT==6 ;SIZE OF BYTES (Do not change!) +DEFSYM UFDBPW==36./UFDBYT ;NUMBER OF BYTES PER WORD + + ;RANDOM INFO IN UFD +DEFSYM UDESCP==0 ;FS PNTR TO DESC AREA +DEFSYM UDNAMP==1 ;PNTR TO ORG OF NAME AREA +DEFSYM UDNAME==2 ;USER NAME (FOR CHECKING) +DEFSYM UDBLKS==3 ;LEFT HALF HAS AMOUNT OF SPACE ALLOCATED (NOT USED + ; CURRENTLY BY SYSTEM), RIGHT HALF HAS NUMBER OF BLOCKS USED. +DEFSYM UDALLO==4 ;IF NONZERO, LEFT HALF HAS DISK NUMBER, RIGHT + ; HALF HAS AMOUNT OF SPACE ALLOCATED +DEFSYM UDDESC==11. ;FIRST LOC AVAIL FOR DESC + + ;UFD DESCRIPTORS + ;0 => FREE 1-UDTKMX => TAKE NEXT N + ;UDTKMX+1 THRU UDWPH-1 => SKIP N-UDTKMX AND TAKE ONE + ;UDWPH => WRITE-PLACE-HOLDER + ;40 BIT SET => LOAD ADDRESS. LOWER 5 BITS PLUS NEXT NXLBYT (2) + ; CHARS (17 BITS IN ALL) + ;40 BIT & 20 BIT => "FUNNY" BLOCK IF DMDSK. WHAT IS THIS, ANYWAY? + ;END BY 0 + + ;IF LINK DESCR + ;6 CHAR OR UNTIL ; = SYS NAME. MUST HAVE NO CHAR = 0 IN THIS OR NEXT 2 NAMES + ;NEXT CHAR QUOTED BY : (FOR NAMES WITH : OR ;) + ;NEXT CHAR N1 + ;NEXT CHAR N2 + ;END BY 0 + +DEFSYM UDTKMX==12. ;HIGHEST "TAKE N" CODE +DEFSYM UDWPH==31. ;PLACE HOLDER ON WRITE (OR NULL FILE) +DEFSYM UDSKMX==UDWPH-UDTKMX-1 ;# BLOCKS THAT CAN BE SKIPPED +DEFSYM NXLBYT==2 ;# ADDITIONAL BYTES FOR LOAD ADDR + ;IN SYSTEM THIS IS DEFINED AT FRONT OF FILE + + ;NAME AREA DATA + +DEFSYM LUNBLK==5 ;WDS/NAME BLK +DEFSYM UNFN1==0 ;FIRST FN +DEFSYM UNFN2==1 ;SECOND FN +DEFSYM UNRNDM==2 ;ALL KINDS OF RANDOM INFO +DEFSYM UNDSCP==1500,, ;PNTR TO DESC +DEFSYM UNPKN==150500,, ;PACK # +DEFSYM UNLINK==1 ;LINK BIT +DEFSYM UNLNKB==220100,, +DEFSYM UNREAP==2 ;IF 1, DONT REAP FILE +DEFSYM UNWRIT==4 ;OPEN FOR WRITING +DEFSYM UNMARK==10 ;GC MARK BIT +DEFSYM UNCDEL==20 ;DEL WHEN CLOSED +DEFSYM DELBTS==20 ;DELETED -- IGNORE +DEFSYM UNIGFL==24 ;BITS TO IGNORE FILE +DEFSYM UNWRDC==301200,, ;WORD COUNT OF LAST BLOCK MOD 2000 +DEFSYM UNDUMP==400000 ;HAS BEEN DUMPED +DEFSYM UNDATE==3 ;DATE ETC. +DEFSYM UNTIM==2200,, ;COMPACTED TIME OF CREATION +DEFSYM UNYMD==222000,, ;Y,M,D OF CREATION +DEFSYM UNMON==270400,, ;MONTH +DEFSYM UNDAY==220500,, ;DAY +DEFSYM UNYRB==330700,, ;YEAR +DEFSYM UNREF==4 ;REFERENCE DATE SAME AS LEFT HALF OF UNDATE +DEFSYM UNREFD==222000,, ;REFERENCE DATE BYTE POINTER +DEFSYM UNAUTH==111100,, ;MFD INDEX OF AUTHOR, ALL 1=> NO DIRECTORY +DEFSYM UNBYTE==001100,, ;FILE BYTE SIZE AND LENGTH INFO. + ;LET S=BITS PER BYTE, C=COUNT OF UNUSED BYTES IN LAST WD + ;400+100xS+C S=1 TO 3 C=0 TO 35. + ;200+20xS+C S=4 TO 7 C=0 TO 8 + ;44+4xS+C S=8 TO 18. C=0 TO 3 + ;44-S S=19. TO 36. C=0 + ;NOTE THAT OLD FILES HAVE UNBYTE=0 => S=36. + +IF1 IFDEF NUDSL, IFG NUDSL*LMNBLK+LMIBLK-2000,.ERR MFD LOSES + +IFN $$TEMP,EXPUNG DEFSYM diff --git a/src/syseng/modems.20 b/src/syseng/modems.20 new file mode 100755 index 00000000..63737d6a --- /dev/null +++ b/src/syseng/modems.20 @@ -0,0 +1,96 @@ +; -*- Midas -*- + +title MODEMS - Initialize Hairy Modems +; Here in the future, modems are smarter than we are. + +a=:1 +b=:2 +c=:3 +d=:4 +e=:5 +t=:6 +tt=:7 + +chttyo=:10 + +slose=:.lose %lssys +quit=:.logout 1, +tyo=:.iot chttyo, + +define syscall name,args + .call [setz ? sixbit /name/ ? args(400000)] +termin + +go: syscall sstatu,[repeat 6,[ ? movem a]] + slose + movsi b,-lmchtab + came a,mchtab(b) + aobjn b,.-1 + jumpge b,done + move a,tabtab(b) +loop: hlrz b,(a) + syscall ttyvar,[movei 400000(b) ? [sixbit /TTYTYP/] ? movem c] + slose + trnn c,%tydil + jrst next + idivi b,10 + hrlzi c,'T00(c) + lsh b,24. + add b,c + syscall open,[[.uao\%tjsio,,chttyo] ? b] + jrst next + syscall ttyget,[movei chttyo ? movem b ? movem b ? movem b] + slose + tlne b,%tscns + jrst next ; Don't diddle our own console! + .reset chttyo, + syscall ttyset,[movei chttyo + [<010101,,010101>*%tgact] + [<010101,,010101>*%tgact]] + slose + hrrz b,(a) + hrli b,440700 + jrst outlp1 + +; Each character is output preceeded by a 1/3 second pause. +; Except ^P just causes a 2 second pause. +; Except ^Q outputs the next character immediately. +outlpq: ildb c,b +outlp: tyo c +outlp1: ildb c,b + cain c,^Q + jrst outlpq + cain c,^P + jrst [ MOVEI T,60. ? .SLEEP T, ? JRST OUTLP1 ] ; 2 secs + movei t,10. ; 1/3 sec + .sleep t, + jumpn c,outlp + .close chttyo, +next: aobjn a,loop +done: quit + +mchtab: sixbit /AI/ + sixbit /MC/ +lmchtab==:.-mchtab + +tabtab: -laitab,,aitab + -lmctab,,mctab +ifn <.-tabtab>-lmchtab, .err TABTAB wrong size + +; On AI, T03 and T04 are connected to shitty maxel modems. +aitab: 3,,maxel + 4,,maxel +laitab==:.-aitab + +; On MC, T01 and T02 are connected to shitty maxel modems. +mctab: 1,,maxel + 2,,maxel +lmctab==:.-mctab + +maxel: asciz "+++îîîîîIîATZîATS0=1S2=26E0Q1î" + +cnstnts: +constants +variables + +end go diff --git a/src/syseng/netwrk.266 b/src/syseng/netwrk.266 new file mode 100755 index 00000000..96d44bed --- /dev/null +++ b/src/syseng/netwrk.266 @@ -0,0 +1,2705 @@ +;-*- Mode:MIDAS; -*- + +; Netwrk subroutines +; Canonical location is [MIT-AI] SYSNET;NETWRK > +; All changes must be made or copied to this location, +; or they will be lost! +; +; New version partially fixed for HOSTS3, 2/17/83. --KLH +; ITS/20X version, 4/8/83. --Ian +; +; $$ARPA is understood to mean Internet; any address with NE%UNT off +; qualifies as an Internet address. +; +;*************************************************************************** +;******* In order to help clean things up and keep stuff working, +;******* please enter here the names of any programs you are aware of +;******* which insert this file! This will assure that future changes +;******* will not break your favorite software. +; AI:SYSENG;CRTSTY +; AI:SYSENG;TELSER +; AI:SYSEN1;HSTLOK +; AI:SYSEN1;PWORD +; AI:SYSEN1;UP +; AI:SYSEN2;PEEK +; AI:SYSEN2;TELNET +; AI:KSC;COMSAT +; AI:SYSNET;FTPS +; AI:SYSNET;FTPU +; AI:KSC;QMAIL +; MX:MT;NTELSUP +; AI:SYSEN1;SENDER +; AI:BAWDEN;PROBE +; AI:SYSENG;DUMP + + +IFNDEF ITS,[ + IFE .OSMID-SIXBIT/ITS/,ITS==1 + .ELSE ITS==0 +];IFNDEF ITS +IFNDEF 20X,[ + IFE .OSMID-SIXBIT/TWENEX/,20X==1 + .ELSE 20X==0 +];IFNDEF 20X +IFNDEF 10X,[ + IFE .OSMID-SIXBIT/TENEX/,10X==1 + .ELSE 10X==0 +];IFNDEF 10X +TNX==20X\10X ; This is the normally used switch. + +.AUXIL ;Don't mention all my symbols in crefs of programs that use me. + +.BEGIN NETWRK + +;Calling Conventions: +; +;All subroutines herein are called by PUSHJ P, +;and take their skip return if successful, non-skip if error. +;Arguments are passed in ACs A,B,C,D,E. ACs T and TT are freely smashable. +;However, "low level" subroutines generally take arguments and +;return values in T and TT and leave A-E alone. +;Subroutines may alter A-E as documented with each routine. +;The only ACs assumed are A,B,C,D,E,T,TT,P. TT=T+1 is assumed. +; +;The following externally defined symbols are assumed: +; +;GETCHR Routine to read character for HOSTNM/SYMGET routine. +; Returns in T, clobbers TT, skip return unless no chars available. +; +;PUTCHR Routine to write character for HOSTNM/SYMGET and ANALYZE routines. +; Char is passed in T (!!). Mustn't clobber any ACs. Never skips (!!). +; +;SPCHAN Routine to handle special characters for HOSTNM/SYMGET. +; Char is passed in T, number so far read in TT. +; Non-skip return to restart reader, skip to ignore char. +; +;DEBUG Nonzero if debugging. SERVE doesn't time out, and .VALUE'S +; if anything bad happens. +; +;The usual values for ITS predefined symbols are assumed. +; +;The NETWRK subroutines are enclosed in a MIDAS begin block to avoid +;confusion in the local tags. All code produced is pure. Any impure +;locations needed are created as MIDAS variables (eg, .VECTOR). + +;Print file version + .TYO6 .IFNM1 + .TYO 40 +IFN ITS,.TYO6 .IFNM2 +IFN TNX,[ +DEFINE TYPN ARG +PRINTX "ARG" +TERMIN +RADIX 10. + TYPN \.IFVRS +RADIX 8. +] ;TNX + PRINTX / included in this assembly. +/ + +qmtch==.qmtch ;In case the .INSRTer didn't have this set, turn it on so that +.qmtch==-1 ;we use "foo" construct, for other-assembler compatability. + +;The following symbols are used to select only necessary routines + +IFNDEF $$HST3, $$HST3==1 ; 1 = use HOSTS3 format and file. +IFNDEF $$HOSTNM, $$HOSTNM==0 ;Host name file lookup routines. +IFNDEF $$SYMGET, $$SYMGET==0 ;Interactive symbol input routine +IFNDEF $$SYMLOOK,$$SYMLOOK==0 ;table lookup routine. +IFNDEF $$HSTMAP, $$HSTMAP==0 ;HSTMAP, HSTUNMAP, HSTSRC host name table rts +IFNDEF $$HSTSIX, $$HSTSIX==0 ;Sixbit host name abbreviation +IFNDEF $$MIT, $$MIT==1 ;Flush "MIT-" in HSTSIX +IFNDEF $$OWNHST, $$OWNHST==0 ;Routine to get own host address +IFNDEF $$HSTCMP, $$HSTCMP==0 ;Routine to compare two host addresses +IFNDEF $$NETSRC, $$NETSRC==0 ;NETSRC routine to get network names +IFNDEF $$ICP, $$ICP==0 ;Initial Connection Protocol +IFNDEF $$SERVE, $$SERVE==0 ;Respond to an ICP (for a server) +IFNDEF $$SYSDBG, $$SYSDBG==0 ;ARPSRV, CHASRV shouldn't handle SYSDBG itself +IFNDEF $$CONNECT, $$CONNECT==0 ;Network Connection Routine (ARPCON, CHACON) +IFNDEF $$SIMPLE, $$SIMPLE==0 ;Simple-transaction for Chaosnet +IFNDEF $$ANALYZE, $$ANALYZE==0 ;Network Error Analysis Routine +IFNDEF $$ERRHAN, $$ERRHAN==0 ;Automatic ANALYZE in ARPCON, CHACON, etc. +IFNDEF $$LOGGING, $$LOGGING==0 ;Network library usage logging +IFNDEF $$UPTM, $$UPTM==1 ;ANALYZ should give estimated time up again +IFNDEF $$CVH, $$CVH==0 ;1 to include host number conversions + +IFNDEF $$LOOK, $$LOOK==0 ;1 to support no network (just lookups) +IFNDEF $$CHAOS, $$CHAOS==0 ;1 to support Chaosnet hosts and rtns +IFNDEF $$ARPA, $$ARPA==0 ;1 to support Arpanet hosts and rtns +IFNDEF $$TCP, $$TCP==0 ;1 to support /TCP switch & routines +IFN $$TCP*$$SYMLOOK,[ + $$ARPA==1 ;arpa must be set for TCP to work here + ] +IFNDEF $$ALLNET,[ ; 1 for lookup rtns to support all nets + IFE $$HST3,$$ALLNET==0 ; Including ones ITS doesn't handle. + .ELSE $$ALLNET==$$ARPA + ] + +IFN $$ARPA,[ +IFNDEF ARPHST, .SCALAR ARPHST +] + +IFN $$TCP,[ +IFNDEF USENCP, .SCALAR USENCP +IFNDEF USETCP, .SCALAR USETCP + ] + +IFNDEF $$PROMPT, $$PROMPT==1 ;1 to use default prompt "Host: " +IFNDEF $$TCPTO, $$TCPTO==15.*30. +IFNDEF $$CHATO, $$CHATO==15.*30. + +;;; Summary of entry-points and calling sequences. +;;; Note that all routines listed here skip-return on success, clobber T and TT. +;;; +;;; SYMGET(E:table_p) => A:symbol_value, B,C,D,E:junk +;;; SYMLOOK(A:input, E:table_p) => B:result_descr, T:numeric_value +;;; HSTMAP(A:page#, B:channel#) => RH(A):next_free_page +;;; HSTUNMAP() +;;; HSTSRC(B:host#) => A:TIP_flag,,name_p, D:site_p +;;; HOSTNM() => A:host#, TT:network#, B,C,D,E:junk +;;; HSTLOOK(A:input) => A:host#, TT:network#, B:result_desc, E:junk +;;; HSTSIX(A:host#) => A:sixbit_host_name +;;; OWNHST(A:network#) => A:host# (address of this machine on that network) +;;; HSTCMP(A:host#,B:host#) => skip iff 2 hosts are the same +;;; NETSRC(B:net#) => A:name_p +;;; ARPICP(A:pin#, B:host#, C:socket#, D:imode,,omode) => clobbers all, opens pin+2,pin+3 +;;; ICPASN(A:pin#, B:host#, C:socket#, D:imode,,omode, E:phase#) +;;; ARPSRV(A:pin#, B:socket#, C:imode,,omode) => B:host#, C:sysdbg, A,D:junk, opens pin+2,+3 +;;; ARPCON(A:pin#, B:host#, C:frn_socket#, D:async,,mode) +;;; CONFIN(A:pin#, , , D:mode) +;;; CHASRV(A:channel#, C:contact_name_p, D:window_size) => B:host#, C:sysdbg, A,D:junk +;;; CHACON(A:channel#, B:host#, C:contact_name_p, D:window_size) +;;; CHASMP(A:channel#, B:host#, C:request, D:answer) +;;; CHALSN(A:channel#, B:zero_or_host#, C:contact_name_p, D:window_size) +;;; TCPCON(A:channel#, B:host#, C:port#) +;;; TCPSRV(A:channel#, B:port#) => B:host#, C:sysdbg, A,D:junk +;;; ANALYZE(A:channel#) => prints error message, with no CRLF + +IFE $$LOOK+$$CHAOS+$$ARPA, .FATAL You have to specify at least one network +IFN $$ERRHAN,$$ANALYZE==1 +IFN $$SYMGET,$$SYMLOOK==1 +IFN $$HOSTNM,$$HSTMAP==1 +IFN $$HSTCMP,$$HSTMAP==1 +IFN $$SIMPLE,$$CONNECT==1 + +DEFINE $$LOG +IFN $$LOGGING!TERMIN + +$$LOG,[ +IFE ITS, .ERR Sorry the LOGging feature is only supported under ITS +;;; For logging connections. Example: LOG OPEN,[B,C] +DEFINE LOG NETOP,CRUFT +%%ZZ==1 +PUSHJ P,[ PUSH P,A + PUSH P,[SIXBIT /NETOP/] + IRP CRUFTY,,[CRUFT] + MOVE A,CRUFTY + PUSH P,A + %%ZZ==%%ZZ+1 + TERMIN + MOVEI A,%%ZZ + PUSHJ P,NETWRK"LOGACT + REPEAT %%ZZ, POP P,A + POP P,A + POPJ P, ] +TERMIN +];$$LOG + +NE%UNT==:<1_32.> ; Escape bit indicating non-Internet address +IFN $$HST3,[ +NW$BYT==:301400 ; Byte pointer to network number (approx!) +NE%STR==:<1_33.> ; Escape bit indicating string-type address + ; Useful HOSTS3 full word network # values +NW%CHS==:> ; CHAOSNET +NW%ARP==:<10._24.> ; ARPANET +NW%MIL==:<26._24.> ; MILNET +NW%LCS==:<18._24.> ; MIT-LCS (18) +NW%AI==:<20015,,> ; MIT-AI-NET (128.52) + +; Corresponds to kludge in HOSTS3 that reduces the size of the network table. +DEFINE GETNET AC,(ADDR) +IFNB [ADDR] MOVE AC,ADDR + TDZ AC,[<1_24.>-1] +TERMIN + +IFN 0,[ +DEFINE GETNET AC,(ADDR) +IFNB [ADDR] MOVE AC,ADDR + TLNN AC,(17_32.) ; Check for non-Internet type addrs + TLNN AC,(1_31.) ; Internet address, see if class A net + TDZA AC,[77,,-1] ; Unternet or class A, zap low 3 octets + TLNN AC,(1_30.) ; Class B or C, see which. + TRZA AC,177777 ; Class B network, zap low 2 octets + TRZ AC,377 ; Class C net, only zap 1 low octet +TERMIN +] ;IFN 0 + +] ;$$HST3 +.ELSE [ ; HOSTS2 format stuff +NW%CHS==:7 ;Chaos net +NW%ARP==:12 ;Arpa net +NW%LCS==:22 ;LCS net +;NW%DLN==:26 ;Dial net (not supported by these routines) +NW$BYT==:331000 ; Byte pointer to network number + +DEFINE GETNET AC,(ADDR) + LDB AC,[NW$BYT,,ADDR] +TERMIN +] ;HOSTS2 + +IFN $$CHAOS,[ + IFNDEF $CPKOP,[ + IFN ITS, .INSRT SYSENG; CHSDEF > + .ELSE .INSRT SYSTEM:CHSDEF + ] +] +IFN ITS,[ +.CALL==43_33 ;IN CASE OUR .INSRT'ER USES CALRET .CALL MACRO. +DEFINE SYSCAL NAME,ARGS +.CALL [SETZ ? SIXBIT /NAME/ ? ARGS ((SETZ))] +TERMIN +];ITS + +POP2J: SUB P,[1,,1] ;Exits used in a few places. +POP1J: SUB P,[1,,1] +CPOPJ: POPJ P, + +POPJ1: AOS (P) + POPJ P, + +IFNDEF NWLOSS,[ ; SO .INSRT'ER CAN SUBSTITUTE SOMETHING FOR LOSSAGE CHKS +IFN ITS,[ +DEFINE NWLOSS + .LOSE +TERMIN +];ITS +IFN TNX,[ +DEFINE NWLOSS + HALTF +TERMIN +];TNX +];NWLOSS + +IFN $$SYMGET+$$SYMLOOK,[ +.SCALAR HSTNMF ;Document these! +.SCALAR NOABRV +.SCALAR NTSPCF +] + +IFN $$SYMGET,[ + +;Interactive symbol readin and lookup. +; +; Call: MOVE E,TABLEP +; PUSHJ P,SYMGET +; error +; value of symbol now in A. +; +;Smashes B, C, D, E, T, TT. +; +; TABLEP should be an aobjn ptr to the table +; of symbols from which user input is to select. +; Num is an arbitrary 18-bit field derived from the table. +; The format of the table is: +; [asciz/prompt string/] +; --> value1,,[asciz/upper-case-symbol-1/] +; value2,,[asciz/upper-case-symbol-2/] +; . . . +; Note that this table is an argument to the SYMGET entry. The +; HOSTNM entry uses the table from the HOSTS3 file, not in the same format. +; +;Subroutines used: +; GETCHR, PUTCHR, SPCHAN (see previous page for call sequences) +; +; GETCHR subroutine to get a character (1 arg) +; PUTCHR subroutine to type a character (1 arg). +; input is echoed/completed through PUTCHR +; SPCHAN if a character other than a letter, a number, +; a hyphen, a period, a space, or a CR is seen, +; SPCHAN is called with the char in T. Variable NUMGOT +; will have value of number read thus far (-1 if none). +; Non-skip return restarts reader, skip return ignores char +; and continues. +; + +.VECTOR RCPBUF(6) ;input buffer for this routine +.SCALAR CHRCNT,NUMGOT + +;Register Usage +; +;A octal host number accum - scratch, if reading name. +;B decimal host number accum - scratch, if reading name. +;C scratch. +;D byte pointer into input buffer +;E (aobjn) pointer to table +;T character or random data +;TT miscellany + +IFN $$PROMPT,[ +PROMPT: [ASCIZ /Host: /] ; default prompt +]; IFN $$PROMPT + +SYMGET: ;interactive symbol input routine, with completion. + SETZM HSTNMF ;Say we are not using the host names table (it has no prompt string). +HSTNM1: REGO: + SKIPN HSTNMF + SKIPA TT,-1(E) ;prompt + MOVE TT,PROMPT + PUSHJ P,ZTYPE +GO3A: MOVEI D,RCPBUF ;PTR TO SPEC STRING + HRLI D,440700 ;PTR INTO COLLECTED STRING + SETZM CHRCNT ;COUNT OF CHARS IN STRING + SETOM NUMGOT ; Value of number read thus far + +GO1: PUSHJ P,GETCHR ;GET INPUT CHARACTER + MOVEI T,^M ;NO CHARS AVAIL SAME AS A CR. + JUMPE T,GO1 ;IGNORE NULLS. + CAIL T,"a" + CAILE T,"z" + CAIA ;NOT LOWER CASE + SUBI T,40 ;CONVERT LOWER CASE TO UPPER + CAIE T,12 + CAIN T,15 + JRST GOTRM ;E-O-L MEANS USER DONE WITH SPEC. + CAIN T,40 + JRST GOTRM0 ;SPACE COMPLETE BUT DON'T TERM + CAIN T,177 ;RUBOUT CAUSES COMPLETE RESTART + JRST [ MOVEI TT,[ASCIZ\? +\] ? PUSHJ P, ZTYPE + JRST REGO ] + CAIE T,"?" + CAIN T,33 ;? OR ALT MEANS LIST ALL POSSIBLE HOSTS, + JRST GOTALT ;GIVEN TYPEIN THUS FAR. + JRST GOTC + +BAD1: SUB P,[1,,1] +BAD: MOVEI T,7 ;IF BAD CHAR GIVEN, DING BELL. +GOECH: PUSHJ P,PUTCHR + JRST GO1 + +;GOT A CHARACTER. IS EITHER SPECIAL OR PART OF A NAME + +GOTC: CAIN T,"-" ;BY SPECIAL DISPENSATION, HYPHEN + JRST GOTC00 + CAIN T,"." ; Also allow period as part of name + JRST GOTC00 + CAIN T,"/" ;SLASH AT THIS LEVEL IS JUST A CHARACTER + JRST GOTC00 ;SYML1 WILL HANDLE HOST/IMP AND ADDRESS/NETWORK-NAME CONSTRUCTS + CAIGE T,"0" ;NUMBERS + JRST SPECL + CAIG T,"9" + JRST GOTC00 + CAIGE T,"A" ;LETTERS + JRST SPECL + CAIG T,"Z" + JRST GOTC00 +;OTHERWISE SPECIAL CHARACTER, HANDLE IT +SPECL: MOVE TT,A + PUSHJ P,SPCHAN + JRST GO3A ;RESTART FROM THE BEGINNING + JRST GO1 ;IGNORE THIS CHAR + +;GOT A CHAR. STORE IF IT PLUS STRING THUS FAR MATCHES A NAME, DON'T STORE IF NOT. +;CHAR (NOT ECHOED YET) IS IN T. +GOTC00: PUSH P,D ;PREPARE TO FLUSH THE CHAR IF IT MAKES AN UNDEF SYMBOL. + IDPB T,D ;STORE CHAR IN STRING, FOLLOWED BY A NULL. + PUSH P,D + SETZ TT, + IDPB TT,D + POP P,D + AOS CHRCNT ;INCREMENT COUNT OF CHARS IN STR. + PUSH P,T + MOVEI A,RCPBUF + PUSHJ P,SYML1 ;SEARCH THE TABLE FOR THIS STRING. + JFCL + CAIGE B, + MOVEM T,NUMGOT ; Store number got thus far. + POP P,T + POP P,TT + JUMPN B,GOECH ;NUMBER, OR SYMBOL FOUND OR AMBIGUOUS => THIS CHARACTER IS OK. + SETZ TT, ;SYMBOL UNDEFINED => ZERO OUT THIS CHAR IN THE STRING + DPB TT,D + MOVE D,TT ;BACK UP POINTER TO END OF STRING + SOS CHRCNT + JRST BAD ;AND COMPLAIN. + +;GOT A E-O-L, SEE IF HAVE ENOUGH OF NAME TO RENDER IT UNIQUE. +GOTRM: TDZA C,C ;COMPLETE AND TERMINATE +GOTRM0: SETOM C ;JUST COMPLETE + SKIPG CHRCNT ;HMMM, ANYTHING IN STRING STORED? + JRST BAD ;NO, DING... + MOVEI A,RCPBUF ;ELSE LOOK THE STRING UP. + PUSHJ P,SYML1 + JRST BAD ;UNDEFINED OR AMBIGUOUS => LOSE. + MOVE A,T + MOVE TT,B ;NUMBER => OK, AND DON'T TYPE ANYTHING. RETURN NUMBER IN A. + AOJE TT,WIN + HRRZ TT,(B) ;FOUND AND UNAMBIGUOUS. COMPLETE THE NAME IF ABBREVIATED. + SKIPE HSTNMF + ADD TT,HSTADR ;GET POINTER TO THE FULL NAME. + HRLI TT,440700 + MOVE A,CHRCNT + ILDB T,TT ;IGNORE AS MANY CHARS AS THE USER ACTUALLY GAVE. + JUMPE T,GOTRM2 ;HANDLE USER ABBREVIATION AND /NET FORMS RIGHT + SOJG A,.-2 +GOTRM1: ILDB T,TT + JUMPE T,GOTRM2 + IDPB T,D ;AS WE COMPLETE THE NAME, STORE THE CHARS INTO THE ARG + AOS CHRCNT ;SO THAT IF THIS IS A SPACE, THE FOLLOWING CR DOESN'T + PUSHJ P,PUTCHR ;TYPE THE SAME STUFF OUT AGAIN. + JRST GOTRM1 + +GOTRM2: HLRZ A,(B) ;WIN. RETURN LH. OF TABLE WORD. + SKIPE HSTNMF ;NORMALLY IS SYMBOL VALUE, BUT IF READING HOST NAME, IS FILE- + SETO TT, ;RELATIVE ADDRESS OF SITE TABLE ENTRY, TT NON-ZERO MEANS NOT NUMBER +WIN: JUMPN C,GO1 ;SHOULD TERMINATE? NO => GO READ MORE CHARS. + PUSHJ P,CRLF ;YES, GIVE CRLF + JRST POPJ1 ;AND RETURN WINNING NUMBER IN A + +;GOT ? OR ALT, LIST ALL NAMES POSSIBLE AT THIS STAGE. +GOTALT: SKIPN CHRCNT + JRST GO1 ;ALTMODE OR ? AFTER A NUMBER IS A NO-OP. + MOVEI A,RCPBUF + SETOM NOABRV + PUSHJ P,SYMLA ;SEARCH FOR ALL POSSIBLE ALTERNATIVES. + JFCL + TLNN B,-1 + HRLS B ;IF ONLY ONE, SET IT UP AS RANGE ,,. + MOVE TT,B + AOJE TT,GO1 ;IF ARG IS A NUMBER, DON'T TYPE ANYTHING. + PUSHJ P,CRLF + HLRZ A,B ;A POINTS TO FIRST, RH(B) POINTS TO LAST. +GOTAL1: HRRZ TT,(A) ;GET THE ADDR OF THE NEXT POSSIBLE MATCH'S NAME STRING + SKIPE HSTNMF + ADD TT,HSTADR + PUSHJ P,ZTYPE ;TYPE IT. + PUSHJ P,CRLF + ADDI A,1 + CAIG A,(B) + JRST GOTAL1 + SKIPN HSTNMF ;GIVE PROMPT STRING AGAIN + SKIPA TT,-1(E) + MOVE TT,PROMPT + PUSHJ P,ZTYPE + MOVEI TT,RCPBUF ;FOLLOWED BY THE ARG CHARS WE HAVE SO FAR. + PUSHJ P,ZTYPE + JRST GO1 + +] ;END IFN $$SYMGET + +IFN $$SYMLOOK,[ + +; SYMLOOK - Non-incremental hostname/hostaddr (symbol) lookup routine +; called by the incremental one. +;Numbers are normally octal, but a "." at the end implies decimal. +;Decimal host slash decimal Imp and any address slash network name are allowed. +; The decimal "octet" form is allowed, right justified. +;In the address slash network-name form, the argument is smashed then restored! +; + ; A/ ; Can also be 0,, or -1,, +; E/ ; e.g. -tablelen,,table +; Returns .+1 if fail: +; B/ 0 for an undefined sym, or ,, for an ambiguous one. +; Returns .+2 if won: +; B/ addr of table entry for symbol we found. +; or -1 if argument was a number; value returned in T. +; Clobbers T, TT. + +SYMLOOK: + SETZM HSTNMF +SYML1: SETZM NOABRV +SYMLA: PUSH P,C + PUSH P,D + HLRZ TT,A + SKIPE TT ;If A is an address, + CAIN TT,-1 ;or HRROI-style TWENEX string pointer, + HRLI A,440700 ;then turn into canonical PDP-10 BP + MOVE TT,A + MOVE T,A + ILDB T,T ;First character of string + CAIL T,"0" ;Is the argument a number (starts with a digit)? + CAILE T,"9" + JRST SYML6 + SETZB C,D ;Yes => accumulate octal number in C, decimal in D. +SYML7: ILDB T,TT + CAIL T,"0" + CAILE T,"9" + JRST SYML8 + IMULI C,10 + IMULI D,10. + ADDI C,-"0"(T) + ADDI D,-"0"(T) + JRST SYML7 + +SYML8: CAIN T,"/" + JRST SYMSL1 ;Digits followed by slash + CAIE T,"." ;Out of digits => "." means use the decimal number + JRST SYML9 ;(else use the octal). + MOVE C,D + ILDB T,TT + CAIN T,"/" ;OK to have both a decimal point and a slash + JRST SYMSL1 + JUMPE T,SYML9 + CAIL T,"0" ; Another number? + CAILE T,"9" + JRST SYML9 + + ; Aha, have num.num so keep going in this vein. + MOVEI D,-"0"(T) ; Initialize D with 1st digit of 2nd number +SYML41: ILDB T,TT + CAIL T,"0" + CAILE T,"9" + JRST [LSH C,8. + ADDI C,(D) + SETZ D, + CAIN T,"." + JRST SYML41 + CAIN T,"/" + JRST SYMSL1 + JRST SYML9] + IMULI D,10. + ADDI D,-"0"(T) + JRST SYML41 + +SYML9: JUMPN T,SYMUND ;Any stray chars after the last digit or the "." => error. + MOVE T,C + SETO B, ;Return the number in T and -1 (=> this is a number) in B. + JRST SYMWIN + +SYMSL1: SKIPN HSTNMF ;Slash only magic if hacking hosts + JRST SYML9 + ILDB T,TT ;Look at character after slash + CAIL T,"0" + CAILE T,"9" + JRST [ADD TT,[070000,,] ; Back up byte-pointer + PUSHJ P,SYMSL4 ; Process slash network-name. + SETZ T, + JRST SYML9 ] + +IFE $$ARPA, JRST SYML9 +IFN $$ARPA,[ + MOVE C,D ;Number slash number, use decimal + MOVEI D,-"0"(T) +SYMSL2: ILDB T,TT + CAIL T,"0" + CAILE T,"9" + JRST [ +IFN $$HST3,[ LSH C,16. ? DPB D,[002000,,C] ; Move HOST over and add IMP + ADD D,[NW%ARP] + MOVE TT,[NW%ARP] + MOVEM TT,NTSPCF + +];$$HST3 +.ELSE [ DPB D,[112000,,C] ;Deposit IMP number into HOST number + MOVEI D,NW%ARP ;And this is obviously Arpa net + DPB D,[NW$BYT,,C] +];HOSTS2 + JRST SYML9 ] + IMULI D,10. + ADDI D,-"0"(T) + JRST SYMSL2 +];$$ARPA + + +;;Subroutine to read network name and set NTSPCF to network number +;; Note if HOSTS3 this is a full-word value. +IFE $$ALLNET,[ + +SYMSL4: MOVEI D,0 +SYMSL5: ILDB T,TT + JUMPE T,SYMSL6 + LSH D,6 + CAIL T,"a" + SUBI T,40 + IORI D,-40(T) + JRST SYMSL5 + +SYMSL6: IRPS FLAG,,[$$CHAOS $$ARPA $$TCP $$TCP + ]NAME,,[CHAOS ARPA TCP NCP + ]NUM,,[NW%CHS NW%ARP NW%ARP NW%ARP] +IFN FLAG,[ ;Make sure we claim to support this network + MOVE TT,[SIXBIT \NAME\] + PUSHJ P,SYMSXC + MOVE T,[NUM] ;Prefix -- set it +];FLAG + TERMIN +IFN $$TCP,[ + MOVE TT,[SIXBIT \TCP\] + PUSHJ P,SYMSXC + JRST [ SETOM USETCP + SETZM USENCP + JRST .+1] + MOVE TT,[SIXBIT \NCP\] + PUSHJ P,SYMSXC + JRST [ SETOM USENCP + SETZM USETCP + JRST .+1] +] + JUMPE T,[POP P,T ? JRST SYMUND] ;Unknown network name, barf + MOVEM T,NTSPCF + POPJ P, + +;; Compares sixbit arg in D with sixbit Network name in TT. +;; Returns .+1 if arg is prefix of net name +;; .+2 otherwise + +SYMSXC: PUSH P,D + JUMPE D,SYMSX1 ; Don't loop forever if arg is 0 + TLNN D,770000 ; Shift until high byte is non-zero + JRST [ LSH D,6 ? JRST .-1 ] + TRNN D,77 ; Shift both until low char non-zero + JRST [ LSH D,-6 ? LSH TT,-6 ? JRST .-1 ] + CAMN D,TT + CAIN D,0 +SYMSX1: AOS -1(P) + POP P,D + POPJ P, + +];$$ALLNET +IFN $$ALLNET,[ +;; Like SYMCMP, but user's string needn't start on word boundary. +;; Compare strings, address of one in T, Byte Pointer to another in C. +;; Smash T, TT, but NOT A, B, C, or D + +SYMCMC: PUSH P,C + PUSH P,D + PUSHJ P,SYMCM0 ;Do comparison w/o setting up C + CAIA + AOS -2(P) ; Success, skip return + POP P,D + POP P,C + POPJ P, + +SYMSL4: PUSH P,C + MOVE C,TT ;ptr to string + MOVE T,HSTADR + ADD T,NETPTR(T) ;Ptr to network tables + MOVN D,(T) ;Count of networks + HRLZS D ;Prepare AOBJN ptr + HRRI D,2(T) ;Ptr to first network +SYSL4A: HLRZ T,NTLNAM(D) ;Ptr to host string + ADD T,HSTADR + PUSHJ P,SYMCMC ;Is this the network we were given? + JRST SYSL4B ; Nope, try next + + MOVE T,NETNUM(D) ;Get the network number + MOVEM T,NTSPCF ;Remember that we specified it + POP P,C + POPJ P, + +SYSL4B: MOVE T,HSTADR ;Find start of NETWORK table + ADD T,NETPTR(T) + ADD D,1(T) ;2nd word is size of entries + ADD D,[1,,0] ;Update the counter + JUMPL D,SYSL4A ;Try next match + POP P,C + POP P,(P) + JRST SYMUND ;Else fail. + +]; $$ALLNET + +;Here to start processing an arg which is not a number. +SYML6: MOVE B,E + ILDB T,TT ;Check for slash and network name + JUMPE T,SYML2 ;None found + CAIE T,"/" + JRST SYML6 + MOVEI T,0 ;Ugh, barf, clobber the argument + DPB T,TT + PUSH P,TT + PUSHJ P,SYMLA ;Go do that + JRST [ POP P,TT ? MOVEI T,"/" ? DPB T,TT ? JRST SYMLZ] ;Lost, propagate, fixing arg + POP P,TT ;Note, recursive call didn't return anything in T + MOVEI T,"/" ; since this wasn't a number + DPB T,TT ;Fix argument + PUSH P,TT ;Don't barf at / with nothing after it yet + ILDB T,TT + POP P,TT + CAIE T,0 + PUSHJ P,SYMSL4 ;Process network-name argument + JRST SYMWIN ;And take success return + +SYML2: HRRZ T,(B) ;Get the next symbol's name from the table. + SKIPE HSTNMF + ADD T,HSTADR + PUSHJ P,SYMCMP ;Does the argument in A abbreviate it? + CAIA + JRST SYML3 ;Yes, we have found the first match. + AOBJN B,SYML2 +SYMUND: SETZ B, ;There is no match. Return 0. + JRST SYMLZ + +SYML3: PUSH P,B ;Remember where the first match is, and find the last. +SYML4: AOBJP B,SYML5 + HRRZ T,(B) ;Get the next symbol's name from the table. + SKIPE HSTNMF + ADD T,HSTADR + PUSHJ P,SYMCMP ;Does the argument in A abbreviate it? + JRST SYML5 ;No => we have gone past the last match. + JRST SYML4 + +SYML5: SUB B,[1,,1] ;B points at last match. + CAMN B,(P) ;Last and first match are the same table entry? + JRST SYMLW ;Then that one is the value. + MOVE TT,(P) + PUSH P,A + HLLZ A,(B) +SYML5A: HLLZ T,(TT) + CAME T,A + JRST SYML5B + CAME TT,B + AOBJN TT,SYML5A ;If all names have the same value, then just + MOVEM B,-1(P) ;return the last name, e.g. for XEROX.ARPA + JRST SYMLW1 ;and XEROX.COM, return XEROX.COM + +SYML5B: MOVE A,-1(P) ;A gets the symbol name of the first match + HRRZ A,(A) + SKIPE HSTNMF + ADD A,HSTADR + HRLI A,440700 + HRRZ T,(B) + SKIPE HSTNMF ;and T gets the name of the last match. + ADD T,HSTADR + SKIPN NOABRV ;If processing "BBN?", show all names starting with BBN + ;even though "BBN" by itself is a valid name. + PUSHJ P,SYMCMP ;if the first match is an abbreviation of the last, + JRST SYMLL +SYMLW1: POP P,A ;then it's no ambiguity; the first wins. +SYMLW: POP P,B + ANDI B,-1 +SYMWIN: POP P,D + POP P,C + JRST POPJ1 + +SYMLL: POP P,A ;Here if argument is really ambiguous. + HRL B,(P) ;produce 1st match addr,,last match addr. + SUB P,[1,,1] +SYMLZ: POP P,D + POP P,C + POPJ P, + +;Compare the ASCIZ string <- A with the one <- T. +;Skip if the one in A is an initial segment of the one in T. +;We clobber C, D, T and TT but NOT A. + +SYMCMP: MOVE C,A +; HRLI C,440700 ;Already a BP now. +SYMCM0: HRLI T,440700 +SYMCM1: ILDB TT,T + ILDB D,C + JUMPE D,POPJ1 ;1st string ended and no mismatch => win. + CAIL D,140 + SUBI D,40 ;Ignore case in the string in A. Assume string in T is all upper. + CAME D,TT + POPJ P, ;mismatch => lose. + JRST SYMCM1 + +IFE $$HSTMAP,.SCALAR HSTADR + +] ;end IFN $$SYMLOOK + +IFN $$HSTMAP,[ + +.SCALAR HSTADR ;Address of HOSTS3 file is stored here. +.SCALAR HSTABN ; AOBJN page pointer to HOSTS3 + +;The format of the compiled HOSTS3 file is: +; NOTE THIS IS NOT COMPLETELY ACCURATE. See the file +; AI:SYSNET;HOSTS3 > for an uptodate description. +HSTSID==:0 ; wd 0 SIXBIT /HOSTS3/ +HSTFN1==:1 ; wd 1 SIXBIT /HOSTS/ usually +HSTVRS==:2 ; wd 2 FN2 of HOSTS file which this was compiled from. +HSTDIR==:3 ; wd 3 SIXBIT /SYSENG/ usually, directory name of source file +HSTMCH==:4 ; wd 4 SIXBIT /AI/ (e.g.), device name of source file +HSTWHO==:5 ; wd 5 UNAME of person who compiled this +HSTDAT==:6 ; wd 6 Date of compilation as sixbit YYMMDD +HSTTIM==:7 ; wd 7 Time of compilation as sixbit HHMMSS +NAMPTR==:10 ; wd 10 Address in file of NAME table. +SITPTR==:11 ; wd 11 Address in file of SITE table. +NETPTR==:12 ; wd 12 Address in file of NETWORK table. + ;....expandable.... + +;NETWORK table +; wd 0 Number of entries in table. +; wd 1 Number of words per entry. (2) +;This table contains one entry for each network known about, sorted +;by network number. A network number is bits 4.8-4.1 of a network +;address; these numbers are assigned by Jon Postel. See symbols below. +;The reason for keeping track of different networks is that the user +;program must make different system calls to use each network. +;Each entry contains: +NETNUM==:0 ; wd 0 network number +NTLNAM==:1 ; wd 1 LH - address in file of name of network +NTRTAB==:1 ; wd 1 RH - address in file of network's address table + +;ADDRESS table(s) +; wd 0 Number of entries in table. +; wd 1 Number of words per entry. (2) +;There is one of these tables for each network. It contains entries +;for each site attached to that network, sorted by network address. +;These tables are used to convert a numeric address into a host name. +;Also, the list of network addresses for a site is stored +;within these tables. +;Each entry contains: +ADDADR==:0 ; wd 0 Network address of this entry (including network number). +ADLSIT==:1 ; wd 1 LH - address in file of SITE table entry +ADRCDR==:1 ; wd 1 RH - address in file of next ADDRESS entry for this site + ; 0 = end of list +ADRSVC==:2 ; wd 2 RH - fileaddr of services list for this address + ; 0 none, else points to SERVICE node of format + SVLCNT==:0 ; <# wds>,, + SVRCDR==:0 + SVLFLG==:1 ; ,, + SVRNAM==:1 + SVCARG==:2 ; Possible additional parameters + +;SITE table +; wd 0 Number of entries in table. +; wd 1 Number of words per entry. (3) +;This table contains entries for each network site, +;not sorted by anything in particular. A site can have more +;than one network address, usually on different networks. +;This is the main, central table. +;Each entry looks like: +STLNAM==:0 ; wd 0 LH - address in file of official host name +STRADR==:0 ; wd 0 RH - address in file of first ADDRESS table entry for this + ; site. Successive entries are threaded together + ; through ADRCDR. +STLSYS==:1 ; wd 1 LH - address in file of system name (ITS, TIP, TENEX, etc.) + ; May be 0 => not known. +STRMCH==:1 ; wd 1 RH - address in file of machine name (PDP10, etc.) + ; May be 0 => not known. +STLFLG==:2 ; wd 2 LH - flags: +STFSRV==:400000 ; 4.9 1 => server site (according to NIC) +STFGWY==:200000 ; 4.8 1 => Internet gateway site + ; wd 2 RH - not used + +;NAMES table: +; wd 0 Number of entries +; wd 1 Number of words per entry. (1) +;This table is used to convert host names into network addresses. +; Followed by entries, sorted by the host name treated as a vector of +; signed integers, looking like: +NMLSIT==:0 ; lh address in file of SITE table entry for this host. +NMRNAM==:0 ; rh address in file of host name + ;This name is official if NMRNAM = STLNAM of NMLSIT. + +; All names are ASCIZ strings, all letters upper case. +; The strings are stored before, after and between the tables. +; All strings are word-aligned, and fully zero-filled in the last word. + +;Network addresses are defined as follows, for purposes of this table: +; 4.9 0 +; 4.8-4.1 network number +; Chaos net (number 7): +; 3.9-2.8 0 +; 2.7-1.1 address (2.7-1.9 subnet, 1.8-1.1 host) +; Arpa net (number 12): (note, old-format Arpanet addresses +; 3.9-3.8 0 never appear in the host table.) +; 3.7-2.1 Imp +; 1.9 0 +; 1.8-1.1 Host + +;Map the host table file SYSBIN;HOSTS3 > into core. +;A should contain the page number to start it at. +;B should contain the channel number to use. +;We skip if we succeed, returning in RH(A) the number of the first page not used up. +HSTMAP: +IFN ITS,[ + SYSCAL OPEN,[ B ? 5000,,.BII ? ['DSK',,] +IFN $$HST3, ['HOSTS3'] +.ELSE ['HOSTS2'] + [SIXBIT />/] ? ['SYSBIN']] + POPJ P, + SYSCAL FILLEN,[B ? 2000,,T] + POPJ P, + JUMPLE T,CPOPJ + MOVEI T,1777(T) ;(round up) + LSH T,-10. + PUSH P,A + LSH A,10. + MOVEM A,HSTADR ;Save in HSTADR the address where we are mapping the file. + POP P,A + MOVNS T ;form AOBJN page ptr for CORBLK + HRL A,T + MOVEM A,HSTABN ; save AOBJN for unmapping + SYSCAL CORBLK,[ 1000,,%CBNDR ;Read-Only. + 1000,,%JSELF ;into self + A ;as specified + B] ;from file open on channel. + POPJ P, + SYSCAL CLOSE,B + POPJ P, + MOVE T,HSTADR +];ITS +IFN TNX,[ +.SCALAR HSTJFN +.SCALAR HSTLEN + + PUSH P,1 ? PUSH P,2 ? PUSH P,3 + PUSH P,A + MOVSI 1,(GJ%SHT\GJ%OLD) +IFN 20X,[ +IFN $$HST3,HRROI 2,[ASCIZ "SYSTEM:HOSTS3.BIN"] +.ELSE HRROI 2,[ASCIZ "SYSTEM:HOSTS2.BIN"] +] ;20X +IFN 10X,[ +IFN $$HST3,HRROI 2,[ASCIZ "HOSTS3.BIN"] +.ELSE HRROI 2,[ASCIZ "HOSTS2.BIN"] +] ;10X + GTJFN + JRST HSTMP7 ; Failed, restore regs. + MOVEM 1,HSTJFN + MOVE 2,[70000,,OF%RD] + OPENF + JRST [MOVE 1,HSTJFN + RLJFN + NOP + JRST HSTMP7] + MOVE 2,[1,,.FBBYV] + MOVEI 3,T + GTFDB ;XXX,,#PAGES + HRRZM T,HSTLEN + HRLZ 1,HSTJFN ;JFN,,FILE PAGE 0 + HRRZ 2,(P) ;PAGE NUMBER WITHIN US (saved on stack) + HRLI 2,.FHSLF + HRRZ 3,T + TLO 3,(PM%CNT\PM%RD) + PMAP +IFN 10X,[ + TRNE 3,-1 ; Counted out yet? + JRST [ HRRI 3,-1(3) ; Bump count down by 1 + TRNE 3,400000 ; and stop if done (count -1) + JRST .+1 + ADDI 1,1 ; Increment # of file page + AOJA 2,.-1] ; and # of process page... then repeat PMAP. +] ;10X + POP P,A + POP P,3 ? POP P,2 ? POP P,1 + MOVE T,A + IMULI T,1000 + MOVEM T,HSTADR +];TNX + MOVE T,HSTSID(T) ;CHECK THAT FIRST WORD OF FILE IS REALLY HOSTS3 +IFN $$HST3,CAME T,[SIXBIT /HOSTS3/] +.ELSE CAME T,[SIXBIT/HOSTS2/] + POPJ P, + JRST POPJ1 + +IFN TNX,[ +HSTMP7: POP P,A + POP P,3 ? POP P,2 ? POP P,1 + POPJ P, +] ;TNX + +; UNMAP HOSTS3. +HSTUNMAP: + SKIPN HSTADR + POPJ P, +IFN ITS,[ + MOVE T,HSTABN ; AOBJN PAGE POINTER TO HOSTS3 + SYSCAL CORBLK,[ 1000,,0 ; DELETE + 1000,,%JSELF ; FROM SELF + T ] + JFCL +];ITS +IFN TNX,[ + PUSH P,1 ? PUSH P,2 ? PUSH P,3 + SETO 1, + MOVE 2,HSTADR + IDIVI 2,1000 ;PAGE# + HRLI 2,.FHSLF + MOVE 3,HSTLEN + TLO 3,(PM%CNT) + PMAP +IFN 10X,[ + TRNE 3,-1 ; Counted out yet? + JRST [ HRRI 3,-1(3) ; Bump count down by 1 + TRNE 3,400000 ; and stop if done (count -1) + JRST .+1 + AOJA 2,.-1] ; Bump # of process page... then repeat PMAP. +] ;10X + POP P,3 ? POP P,2 ? POP P,1 +];TNX + SETZM HSTADR + JRST POPJ1 + +;Given host number in B, return its host name addr in rh(A) and set sign of A +;if the host is a Tip. Skip if successful. No skip => unknown host. +;We also return in D the address of the SITES table entry for the host. +HSTSRC: MOVE A,B + PUSHJ P,STDHST + MOVE B,A + SKIPN HSTADR ;Fail if the HOSTS3 file isn't loaded. + POPJ P, + PUSH P,C + PUSH P,E + PUSH P,T + GETNET C,B ; Get network number + MOVE D,HSTADR + ADD D,NETPTR(D) ;get address of NETWORKS table. + MOVE TT,0(D) ;get # of entries, + MOVE T,1(D) ;and entry size. + ADDI D,2 ;point at first entry. +HSTSR1: CAMN C,NETNUM(D) ;Find appropriate network + JRST HSTSR2 + ADD D,T + SOJG TT,HSTSR1 ;no => look at next entry. +HSTSRX: POP P,T ;unknown network => return non-skipping. + POP P,E + POP P,C + POPJ P, + +HSTSR2: HRRZ D,NTRTAB(D) ;Get address of ADDRESS table for that network + ADD D,HSTADR ;Binary-search it + MOVE C,1(D) ;Words per entry + MOVE E,0(D) ;Number of entries in table + MOVEI D,2(D) ;Base address of table + PUSH P,D +HSTSR3: CAIG E,1 + JRST HSTSR4 ;Search narrowed down to one location + MOVE T,E + LSH T,-1 + MOVE TT,T ;Number of entries in bottom "half" of table + IMUL T,C + ADD T,D ;Probe point + CAMGE B,ADDADR(T) + JRST [ MOVE E,TT ;Move down + JRST HSTSR3 ] + MOVE D,T ;Move up + SUB E,TT + JRST HSTSR3 + +HSTSR4: POP P,T ; Recover base addr of table + CAME B,ADDADR(D) ; Did we get any match at all? + JRST HSTSRX ; Nope, take non-skip return. +HSTSR5: SUBI D,(C) ; Found one! Back up to find 1st match + CAIGE D,(T) ; Make sure we don't back up past beg + JRST HSTSR6 + CAMN B,ADDADR(D) ; As long as we still get a match, + JRST HSTSR5 ; keep backing up. + +HSTSR6: ADDI D,(C) ; Recover from backup. + MOVEI E,(D) ; Save ptr to ADDRESS table + HLRZ D,ADLSIT(D) ; Get address of SITES table entry + ADD D,HSTADR + MOVE A,STLFLG ; Check flags + TLNE A,STFGWY ; to see if this one is a gateway. + JRST [ ADDI E,(C) ; Ugh, gateway. Try to skip it. + CAME B,ADDADR(E) + JRST .+1 ; No good, stuck with this one. + JRST HSTSR6] ; Hurray, try next entry! + HLRZ A,STLNAM(D) ;found the host => get the addr of its name + ADD A,HSTADR ;in our address space. + HLRZ C,STLSYS(D) + ADD C,HSTADR ;also get addr of its system type name + MOVE C,(C) + CAME C,[ASCIZ /TAC/] ;If it's a TAC, + CAMN C,[ASCIZ /TIP/] ; Or a TIP, + TLO A,400000 ; set sign bit of A. + AOS -3(P) ;Take skip return + JRST HSTSRX + +] ;END $$HSTMAP + +IFN $$NETSRC,[ +;;; NETSRC(B:net#) => A:name_p +;;; Convert a network number to a network name + +NETSRC: SKIPN HSTADR ;Fail if the HOSTS3 file isn't loaded. + POPJ P, + PUSH P,C + PUSH P,D + MOVE D,HSTADR + ADD D,NETPTR(D) ;get address of NETWORKS table. + MOVE TT,0(D) ;get # of entries, + MOVE T,1(D) ;and entry size. + ADDI D,2 ;point at first entry. +NETSR1: CAMN B,NETNUM(D) ;Find appropriate network + JRST NETSR2 + ADD D,T + SOJG TT,NETSR1 ;no => look at next entry. + POP P,D ;unknown network => return non-skipping. + POP P,C + POPJ P, + +NETSR2: HLRZ A,NTLNAM(D) ;Get address of name of network + ADD A,HSTADR + POP P,D ;unknown network => return non-skipping. + POP P,C + JRST POPJ1 + +];END $$NETSRC + +IFN $$SYMGET*$$HOSTNM,[ + +;Read in a host name. Works like SYMGET but searches host database. +;We return in A the number of the host, network# in TT. + +HOSTNM: ;Host name reader + PUSHJ P,HSTTBP ;E gets aobjn ptr to NAMES table, and set HSTNMF,NTSPCF + PUSHJ P,HSTNM1 ;Do an interactive symbol table lookup. + POPJ P, ;Failed + ;TT=0 => A has a number + ;else => A has file-relative address of SITE table entry + JUMPE TT,HOSTN1 + ;JRST HOSTN2 +];$$SYMGET*$$HOSTNM + +IFN <$$SYMGET*$$HOSTNM>+<$$SYMLOOK*$$HOSTNM>,[ +;Code to process result of Host-name lookup, returning full address in A +;with network number extracted into TT. +;Address was supplied, file-relative pointer to SITES table entry in A. +HOSTN2: ADD A,HSTADR + SKIPGE TT,NTSPCF ;Explicitly-specified network? + JRST HOSTN4 ;No, try all nets we know about +HOSTN3: HRRZ E,STRADR(A) ;Find an address for SITE in A on network in TT +HSTN3A: ADD E,HSTADR + GETNET T,ADDADR(E) + CAMN T,TT + JRST [ MOVE A,ADDADR(E) ;This is it + JRST POPJ1 ] + HRRZ E,ADRCDR(E) + JUMPN E,HSTN3A ;Try site's next address + POPJ P, ;Not found + +HOSTN4: ;Find a network address for this site +IFN $$CHAOS,[ ;Chaos net is preferred, try it first + MOVE TT,[NW%CHS] + PUSHJ P,HOSTN3 + CAIA + JRST POPJ1 +HOSTN5: +];$$CHAOS +IFN $$ARPA,[ + MOVE TT,[NW%ARP] + PUSHJ P,HOSTN3 + CAIA + JRST POPJ1 +HOSTN6: +];$$ARPA +IFE $$ALLNET,[ + POPJ P, ;Host exists, but not on any network we know about +]; $$ALLNET + +IFN $$ALLNET,[ + HRRZ E,STRADR(A) + JUMPE E,CPOPJ ;No addresses for this site? + ADD E,HSTADR ;where ADDRESS entry is in core + MOVE A,ADDADR(E) ;A J-random Host Address (some random net) + GETNET TT,A ; Extract the network number + JRST POPJ1 ;Success + +]; $$ALLNET + +;Number was supplied, it is in A. Determine what network it is on. +HOSTN1: +IFE $$ALLNET,[ + GETNET TT,A ;Maybe net was specified explicitly as part of number + JUMPN TT,[ ;Yes, make sure is on a network we know about + IRPS FLAG,,[$$CHAOS $$ARPA]NUM,,[NW%CHS NW%ARP] +IFN FLAG,[ CAMN TT,[NUM] + JRST POPJ1 +];FLAG + TERMIN + POPJ P, ] ;Can't find it +]; $$ALLNET + SKIPGE TT,NTSPCF ;Maybe network was specified by name + JRST [ PUSHJ P,STDHST ; Not specified, return standardized number. + JRST POPJ1] +IFN $$HST3, IOR A,TT +.ELSE DPB TT,[NW$BYT,,A] + JRST POPJ1 +];<$$SYMGET*$$HOSTNM>+<$$SYMLOOK*$$HOSTNM> + +IFN $$SYMLOOK*$$HOSTNM,[ + +;HSTLOOK takes args like SYMLOOK and looks in the HOSTS3 NAMES table. +;It returns the same things that HOSTNM returns. It clobbers E, T, TT. +;Also returns in B a pointer like SYMLOOK, or zero if no name lookup won. + +HSTLOOK: + PUSHJ P,HSTTBP ;E gets aobjn ptr to NAMES table, and set HSTNMF,NTSPCF + PUSHJ P,SYML1 ;Do a non-interactive symbol table search. + POPJ P, + MOVE A,T ;If the input was a number + AOJE B,HOSTN1 ;go canonicalize it + HLRZ A,NMLSIT-1(B) ;Else B points at a NAMES table word, so get + SOJA B,HOSTN2 ;the SITE table entry address, go find appropriate net address +];$$SYMLOOK*$$HOSTNM + +IFN <$$SYMGET\$$SYMLOOK>*$$HOSTNM,[ + +;Put in E an aobjn pointer to the HOSTS3 file's NAMES table. Also set HSTNMF. +HSTTBP: SKIPN E,HSTADR + NWLOSS + ADD E,NAMPTR(E) ;Address of NAMES table + MOVE T,1(E) ;Make sure words per entry is 1 + CAIE T,1 + NWLOSS + MOVN T,0(E) ;Negative number of entries + HRL E,T + ADDI E,2 ;E now has an aobjn pointer to the NAMES table. + SETOM HSTNMF ;Say that each address needs HSTADR added to it. + SETOM NTSPCF ;Say that no network explicitly specified + POPJ P, +];<$$SYMGET\$$SYMLOOK>*$$HOSTNM + +IFN $$SYMGET+$$ANALYZE,[ + +;TYPE A CRLF. CLOBBER T. +CRLF: MOVEI T,15 + PUSHJ P,PUTCHR + MOVEI T,12 + PUSHJ P,PUTCHR + POPJ P, + +;TYPE ASCIZ STRING POINTED TO BY TT, CLOBBER T. +ZTYPE: +IFN ITS,[ + HRLI TT,440700 +ZTYPE0: ILDB T,TT + JUMPE T,CPOPJ + PUSHJ P,PUTCHR + JRST ZTYPE0 +];ITS +IFN TNX,[ + PUSH P,1 + HRRO 1,TT + PSOUT + POP P,1 + RETURN +];TNX +];$$SYMGET+$$ANALYZE + +IFN $$HSTSIX,[ + +;Given a host number in A, returns a sixbit abbreviation of +;the name of the host, also in A. Clobbers only T and TT. +;You better call HSTMAP before this. +;Always skip returns. + +HSTSIX: PUSH P,B + PUSHJ P,STDHST + PUSH P,C + PUSH P,D + PUSH P,E + MOVE B,A + PUSHJ P,HSTSRC ;Find the SITES table entry for this host. + JRST HSTSX9 ;none => unknown host. Use HSTnnn. + SUB D,HSTADR ;D gets addr of SITES table entry relative to file + MOVE B,HSTADR ;(for comparison with LH's of NAMES table words). + ADD B,NAMPTR(B) ;Get address of NAMES table. + MOVE T,1(B) ;Make sure 1 word per entry + CAIE T,1 + NWLOSS + MOVE T,0(B) ;T gets number of entries in the table. + SETOB C,E ;E will get the address of the + ; longest name shorter than 7 chars, C its length. + HRRZ TT,A ;Check out the official name first + AOJA B,HSTSX0 + +HSTSX1: ADDI B,1 ;B points at next untried NAMES table entry. + HLRZ TT,NMLSIT(B) + CAME TT,D ;Does this name name the host we are serving? + JRST HSTSX4 + HRRZ TT,NMRNAM(B) ;If so, how long is this name? + ADD TT,HSTADR +HSTSX0: HRLI TT,440700 + PUSH P,TT + PUSH P,TT + SETZ A, +HSTSX2: ILDB TT,(P) + JUMPE TT,HSTSX3 + AOJA A,HSTSX2 + +HSTSX3: POP P,TT ;Flush garbage +IFN $$MIT,[ + MOVE TT,@(P) ;First word of name + TRZ TT,377 + CAMN TT,[ASCII/MIT-/] + CAIG A,6 ;Strip off "MIT-" if longer than 6 characters + JRST .+4 + SUBI A,4 + MOVSI TT,100700 + HLLM TT,(P) +];$$MIT + POP P,TT ;Restore pointer to name + CAIG A,6 ;Fit in 6 characters? + CAMG A,C ;and longer than the previous one? + JRST HSTSX4 + MOVE E,TT ;Yes, save its name's address. + MOVE C,A ;and the length of that one +HSTSX4: SOJG T,HSTSX1 ;look at all the names in the table. + AOJN E,HSTSX5 ;Jump if found a reasonable name + ADD D,HSTADR ;No short name, truncate official one + MOVEI C,"-" ;Also, will remove hyphens from it + HLRZ E,STLNAM(D) + ADD E,HSTADR ;Pointer to name +IFN $$MIT,[ + MOVE A,(E) + TRZ A,377 + CAMN A,[ASCII/MIT-/] + JRST [ HRLI E,100700 + AOJA E,HSTSX5 ] +];$$MIT + TLOA E,440700 +HSTSX5: SUBI E,1 + MOVE B,E ;Get BP to name string. +;B has a B.P. to the name string we are going to use. +;C has "- if we should remove all hyphens from it, otherwise C has a number from 1 to 6. +;Convert the name string to SIXBIT in A. + MOVE D,[440600,,A] + SETZ A, ;Convert name to SIXBIT word in A +HSTSX6: ILDB T,B + JUMPE T,HSTSX7 ;Stop if name string runs out (nice, it all fits). + CAMN T,C ;Remove hyphens if requested to + JRST HSTSX6 ;Note C has number from 1 to 6 or "- + SUBI T,40 + IDPB T,D + TLNE D,770000 ;Stop after getting one full word. + JRST HSTSX6 +HSTSX7: LDB T,D ;If last character is a hyphen, flush it. + CAIN T,'-' + MOVEI T,0 + DPB T,D +HSTSX8: POP P,E + POP P,D + POP P,C + POP P,B + JRST POPJ1 + +;Have to do it numerically. Depends on network. +HSTSX9: + MOVSI A,'NET' + GETNET TT,B + CAMN TT,[NW%CHS] + MOVSI A,'CHS' + CAMN TT,[NW%ARP] + JRST [ MOVSI A,'HST' +IFN $$HST3, LDB T,[002000,,B] ; IMP +.ELSE LDB T,[112000,,B] ;Imp + CAIGE T,100 + TRNN B,774 + JRST .+1 ;Doesn't fit in old-style +IFN $$HST3, LSH B,-16. + ANDI B,3 + LSH B,6 ;Host + DPB T,[000600,,B] ;Convert to old-style + JRST .+1 ] + HRRI A,'000' ;If host number less than 3 digits, pad with zeroes +IFE $$HST3, TLZ B,(.BM (NW$BYT)) ;Host number within network + SETZB T,TT ;T gets sixbit, TT gets char mask + PUSHJ P,HSTS9A + ANDCM A,TT ;Clear characters from A to be clobbered from T + IOR A,T ;Bring in number + JRST HSTSX8 + +HSTS9A: IDIVI B,8 + HRLM C,(P) + SKIPE B + PUSHJ P,HSTS9A + HLRZ C,(P) + LSH T,6 + IORI T,'0'(C) + LSH TT,6 + IORI TT,77 + POPJ P, +];$$HSTSIX + +;;; Standardize host number in A. Clobber T. +;;; No skip-return + +STDHST: +IFN $$HST3, JRST CVH3NA +.ELSE [ + TLNE A,777000 ;Network number specified? + JRST STDHS1 ;Yes, OK +IFN $$ARPA, TLO A,NW%ARP_9 ;No, default to some net we know about +.ELSE IFN $$CHAOS, TLO A,NW%CHS_9 +STDHS1: +IFN $$ARPA,[ + LDB T,[NW$BYT,,A] ;If Arpanet, standardize to new format + CAIN T,NW%ARP + TDNE A,[177777000] + POPJ P, + LDB T,[000600,,A] ;Imp + LDB A,[060200,,A] ;Host + DPB T,[112000,,A] + TLO A,NW%ARP_9 +];$$ARPA + POPJ P, +] ;HOSTS2 + +IFN $$OWNHST+<$$SYMGET*$$HOSTNM>+<$$SYMLOOK*$$HOSTNM>,[ +;;; GIVEN A NETWORK NUMBER IN A (WHICH MUST BE A NETWORK THIS PROGRAM IS +;;; CONDITIONALLY ASSEMBLED TO SUPPORT), RETURN THIS MACHINE'S OWN +;;; ADDRESS ON THAT NETWORK, IN A. CLOBBER T. SKIPS UNLESS HOST NOT ON THAT NET. +OWNHST: +IFN $$ARPA,[ + CAME A,[NW%ARP] + JRST OWNHS1 +IFN ITS,[ + SYSCAL NETHST,[MOVEI -1 ? MOVEM A ? MOVEM A] ;GET OWN ARPANET ADDRESS + POPJ P, ;MUST NOT BE ON ARPANET + PUSHJ P,STDHST ;SYSTEM DOESN'T RETURN NUMBER IN STANDARD FORMAT + JRST POPJ1 +];ITS +IFN TNX,[ + PUSH P,A + PUSH P,1 ? PUSH P,2 ? PUSH P,3 ? PUSH P,4 + MOVEI 1,.GTHSZ + GTHST + CAIA + AOS -5(P) ; Take skip return! + MOVEM 4,-4(P) ; Store result into what will be put in A + POP P,4 ? POP P,3 ? POP P,2 ? POP P,1 + POP P,A ;ALREADY IN INTERNET FORMAT +];TNX + +OWNHS1: +];$$ARPA + +IFN $$CHAOS,[ + CAME A,[NW%CHS] + JRST OWNHS2 +IFN ITS,[ + MOVE A,[SQUOZE 0,MYCHAD] + .EVAL A, + POPJ P, ;MUST NOT BE ON CHAOS NET +];ITS +IFN TNX,[ + PUSH P,A + PUSH P,1 ? PUSH P,2 + MOVE 1,[SIXBIT "CHSTAT"] + SYSGT + HRR 1,2 ;TABLE# + HRLI 1,2 ;WORD#2,,TABLE# + GETAB + JRST [POP P,2 ? POP P,1 + POP P,A ? POPJ P,] + MOVEM 1,-2(P) + POP P,2 ? POP P,1 + POP P,A +];TNX +IFN $$HST3, IOR A,[NW%CHS] +.ELSE TLO A,NW%CHS_9 + JRST POPJ1 +OWNHS2: +];$$CHAOS + POPJ P, ;Some network I don't know about +];$$OWNHST+<$$SYMGET*$$HOSTNM>+<$$SYMLOOK*$$HOSTNM> + +;;; Routine to compare two hosts +IFN $$HSTCMP,[ +;; Take host #'s in A and B, and skip if they refer to the same host. +;; Clobber no AC'S +;; +;;CALL: MOVE A,[HOST] +;; MOVE B,[HOST] +;; PUSHJ P,HSTCMP +;; different or error (unknown host or unmapped HOSTS3 table) +;; same + +HSTCMP: CAMN A,B ;Trivial case + JRST POPJ1 + PUSH P,A ;Clobber no AC's + PUSH P,B + PUSH P,T + PUSH P,D + PUSH P,D ;Get's SITE table entry + PUSHJ P,HSTSRC ;Check this one out + JRST HSTCM9 ; Non-existant or not mapped + MOVEM D,(P) ;Remember this site table entry + MOVE B,-4(P) ;Get the other host # + PUSHJ P,HSTSRC ;and look up it's SITE table entry + JRST HSTCM9 + MOVE T,(P) ;Recover the first SITE table entry + CAMN T,D ;Compare the two entry pointers + AOS -5(P) ; The same! +HSTCM9: POP P,D + POP P,D + POP P,T + POP P,B + POP P,A + POPJ P, + +];$$HSTCMP + +;;; Arpanet connection routines +IFN $$ARPA*ITS,[ +IFN $$ICP,[ + $$CONNECT==1 ;necessary subroutine + +; ARPA NETWORK ICP ROUTINE +; +;Call: MOVEI A,pin ;first of group of 3 channels to use (nonconsecutively numbered) +; ;PIN itself is used only for the ICP. PIN+1 is unused. +; ;PIN+2 and PIN+3 are the in and out sides of the TELNET connection. +; MOVEI B,host ;host number to connect to +; MOVEI C,frnsoc ;foreign socket number to icp through +; MOVE D,[imode,,omode] ;input and output modes as in OPEN on NET device. +; PUSHJ P,NETWRK"ARPICP ;do it. Clobbers A,B,C,D,E,T,TT. +; failed ;A holds the channel which lost. If $$ERRHAN, ANALYZ was called. +; succeeded + +ARPICP: MOVEI E,0 ;synchronous mode +ICPPHS: PUSHJ P,ICP1 ;This is also the phase table + PUSHJ P,ICP2 + PUSHJ P,ICP3 + JRST POPJ1 + +ICPASN: ;asynchronous mode. Same args except E is phase (initially 1). + SKIPL E ;keep calling back with same ACs as returned, until E is zero. + HRREI E,-3 ;asynchronous init + XCT ICPPHS+3(E) ;call appropriate phase + AOJA E,POPJ1 ;and advance to next + +;First phase - connect to ICP socket. +ICP1: PUSH P,D ;Assume that all sockets were closed, so ITS has deallocated any + SETZM SKTBAS ;old set of sockets, and we must ask it for a new set. + HRROI D,040044 ;asynchronous, 32-bit read + PUSHJ P,ARPCON ;initiate connection + JRST POP2J ;lose + POP P,D ;win + POPJ P, + +;Second phase - get server socket number and connect up. +ICP2: PUSHJ P,CONFIN ;finish ICP connection + JRST POP1J ;lose + SYSCAL IOT,[MOVEI (A) ? MOVEM C] ;get foreign socket number +IFE $$ERRHAN, JRST POP1J ;Connection opened but nothing came through, lose +.ELSE JRST [ POP P,C ? JRST ANALNS ] ;Analyze then take error return + ;Due to bug in NCP socket allocation, don't close contact pin yet + ADDI A,2 ;connect our read pin + ADDI C,1 ;to foreign write pin + PUSH P,D + HLROS D ;using input mode, asynchronously + PUSHJ P,ARPCON + JRST POP2J ;lose + ADDI A,1 ;connect our write pin + SUBI C,1 ;to foreign read pin + HRRO D,(P) ;using output mode, asynchronously + PUSHJ P,ARPCON + JRST POP2J ;lose + POP P,D + POPJ P, + +;Third phase - finish up connections. +ICP3: PUSHJ P,CONFIN ;finish write connection + JRST POP1J + SUBI A,1 + PUSHJ P,CONFIN ;finish read connection + JRST POP1J + SYSCAL CLOSE,[MOVEI -2(A)] ;and now close contact pin + .LOSE %LSSYS + POPJ P, + +] ;END IFN $$ICP + +IFN $$SERVE,[ + +;Call: MOVEI A,pin ;first channel number of three consecutive ones. +; ;the first is the ICP listen channel, +; ;the second is the input channel for the TELNET connection, +; ;the third is the output channel for it. +; MOVEI B,icpsoc ;socket to listen for an ICP on. +; MOVE C,[imode,,omode] ;input and output modes as in OPEN on NET device. +; PUSHJ P,NETWRK"ARPSRV ;Listen for and accept an ICP. +; timed out. +; succeeded. B has number of foreign host. +; +;If $$SYSDBG is 0, then connections from hosts locked out by SYSDBG are +;refused, and SERVE fails to skip. +;If $$SYSDBG is 1, then SERVE accepts all connections but returns in C +;a value which is nonzero if the foreign host ought to be locked out by SYSDBG. + +;Clobbers A, D, T and TT. + +$$CONNECT==1 ;We call ARPCON. + +ARPSRV: SYSCAL SSTATU,[MOVEM TT ? MOVEM SYSDBG'] + .LOSE %LSSYS + MOVEI TT,377777 ;If debugging, wait forever. + SKIPN DEBUG + MOVEI TT,30.*60. ;Otherwise time out after 60 sec. +ARPSR1: SYSCAL OPEN,[ A ? 5000,,40065 ? [SIXBIT/NET/] ? B] + JRST ARSVLS ;Open a channel to receive the RFC with. + SYSCAL WHYINT,[ A ? 2000,,T ? 2000,,T] + JRST ARSVLS +ARPSR2: CAIN T,%NSRFC ;Have we an RFC to accept? + JRST ARPSR3 + SKIPN DEBUG ;No => OK only if debugging + POPJ P, ;(so you can start your server before starting the user). + .CALL CONFIC ;So wait for it to change state and look again. + JRST ARSVLS ;[They also serve who hang and wait] + JRST ARPSR2 ;TRY AGAIN + +ARPSR3: HLRZ D,C + TLO D,400000 ;D gets mode for our input socket. + PUSH P,C + SYSCAL RCHST,[ A ? 2000,,C ? 2000,,C ? 2000,,C ? 2000,,B] + .LOSE %LSFIL ;C gets foreign socket ICP'd with. + ;B now has host number of host that ICP'd to us. + TLZ B,777000 ;Make sure network number field is 0 +IFE $$SYSDBG,[ + SKIPL T,SYSDBG ;If system being debugged, may refuse ICP + JRST ARPSR4 + ASH T,-9 ;Set to -1000*host# allowed in + ADD T,B ;Zero if this guy allowed in + JUMPN T,ARSVL2 +ARPSR4: ];$$SYSDBG +;remember that TT has the "sleep time" arguments for NETBLKs, including CONFI1. + SYSCAL NETAC,A + JRST ARSVL1 + ADDI A,1 ;Channel to make input connection on. + ADDI C,3 ;Foreign socket ICP'd with, plus 3, is target for our input. + SETZM SKTBAS' + PUSH P,TT ;See comment 6 lines above! + PUSHJ P,ARPCON + JRST [ POP P,TT ? JRST ARSVL1 ] + MOVE TT,SKTBAS ;Get socket number of our input connection + ADD TT,A + SYSCAL IOT,[1000,,-1(A) ? TT] + .LOSE %LSFIL ;Send our lower socket # to the ICPer. + SYSCAL CLOSE,[1000,,-1(A)] ;Don't need ICP socket any more. + .LOSE %LSFIL + HRRZ D,-1(P) ;Saved C + HRLI D,400000 + ADDI A,1 ;Now open our output connection + SUBI C,1 ;to a foreign socket 1 smaller than that used for our input. + PUSHJ P,ARPCON + JRST [ POP P,TT ? JRST ARSVL1 ] + POP P,TT + POP P,C + PUSHJ P,CONFI1 ;Then wait for the two connections to be finished. + JRST ARSVLS ;TT still has the time period (or by now maybe the + SUBI A,1 ;time to wait until). + PUSHJ P,CONFI1 + JRST ARSVLS +IFN $$SYSDBG,[ + SKIPL C,SYSDBG ;If system being debugged, may disallow + JRST [ SETZ C, ? JRST ARPSR5 ] + ASH C,-9 ;Set to -1000*host# allowed in + TLZ B,777000 ;Clear network number from host number + ADD C,B ;Zero if this guy allowed in +ARPSR5: ];$$SYSDBG + EXCH A,B ;Fix host# returned in B + PUSHJ P,STDHST + EXCH A,B + JRST POPJ1 + +ARSVL2: SYSCAL CLOSE,A + .LOSE %LSFIL +ARSVL1: POP P,C +ARSVLS: SKIPE DEBUG + NWLOSS + POPJ P, + +] ;END IFN $$SERVE + +IFN $$CONNECT,[ + +.SCALAR SKTBAS ; ne 0 => socket number of pin zero + +; ARPA NETWORK CONNECT ROUTINE +; +;Call: MOVEI A,pin ;local its chnl and relative socket number to connect +; MOVE B,host ;host number to connect to +; MOVEI C,frnsoc ;foreign socket number to connect to +; MOVEI D,mode ;mode to open in (RH). Bit 4.9=1 => asynchronous +; PUSHJ P,NETWRK"ARPCON +; lossage ;you may call ANALYZE to get an error message. +; ;If $$ERRHAN is nonzero, we call ANALYZE for you. +; +;Clobbers only T and TT. If using asynchronous mode, +;call CONFIN later (with pin number in A) to finish up. +; +; NOTE: AT PRESENT YOU MUST CONNECT THE LOWEST NUMBERED +; PIN FIRST, DUE TO BUGS IN SOCKET-SET ASSIGNMENT IN NCP. + +ARPCON: MOVE T,A ;Open operand word + HRL T,D ;is mode,,channel + SKIPN TT,SKTBAS ;get base of local socket group + TLO T,10 ;not yet allocated, use gensoc mode + ADD TT,A ;get local sock number to be opened +; TLZ B,777000 ;*** TEMPORARILY CLEAR NETWORK NUMBER UNTIL ITS IS FIXED *** + MOVEM B,ARPHST ;Save last Arpanet host hacked for ANALYZE + .CALL [ SETZ ;open 'er up + SIXBIT/OPEN/ + T ;mode,,channel + ['NET',,] ;arpanet device + TT ;local socket + C ;foreign socket + SETZ B ] ;foreign host +IFN $$ERRHAN,JRST ANALNS +.ELSE POPJ P, + SKIPE SKTBAS + JRST CONNE0 + SYSCAL RCHST,[A ? MOVEM T ? MOVEM T] ;Get local socket, from first pin + .LOSE %LSSYS + SUB T,A ;get socket base + MOVEM T,SKTBAS +CONNE0: JUMPL D,POPJ1 ;asynchronous, return now + ;otherwise, drop into CONFIN + +;Call: MOVEI A,pin ;pin number of connection +; MOVEI D,flags ;20 if listening, 0 if not. Left over from call to ARPCON. +; PUSHJ P,CONFIN ;finish connection +; lossage - you may call ANALYZE to get an error message +; win - clobbers only T and TT + +CONFIN: MOVEI TT,30.*60. ;wait at most one minute + SKIPE DEBUG ;In debug mode, wait forever + MOVSI TT,177777 +CONFI1: MOVEI T,%NSRFS ;Which state we started out in depends + TRNE D,20 ;on whether we were listening or initiating. + MOVEI T,%NSLSN + .CALL CONFIC ;Wait up to time in TT to leave state in T. + .LOSE %LSSYS + CAIE T,%NSOPN ;check good state + CAIN T,%NSINP + JRST POPJ1 + CAIE T,%NSRFC + CAIN T,%NSCLI + JRST POPJ1 +IFN $$ERRHAN,JRST ANALNS ;losing state +.ELSE POPJ P, + +CONFIC: SETZ ;wait for connection to open up + 'NETBLK' + A + T ;wait until not in state in T + TT + SETZM T ;return state + +];$$CONNECT +];$$ARPA*ITS +IFN $$ERRHAN,[ +ANALNS: PUSH P,B ;ANALYZE AND THEN POPJ + PUSH P,C + JRST ANALN1 +] ;END IFN $$ERRHAN + +;;; Chaos network connection routines +IFN $$CHAOS,[ +IFN ITS,[ +IFN $$SERVE,[ + +;Call: MOVEI A,chnl ;Input channel number. That+1 is output channel. +; MOVEI C,contact name ;an ASCIZ string +; MOVEI D,window size +; PUSHJ P,NETWRK"CHASRV +; lossage ;you may call ANALYZE to get an error message. +; ;If $$ERRHAN is nonzero, we call ANALYZE for you. +; +;Returns in B the number of the foreign host. +; +;If $$SYSDBG is 0, then connections from all hosts are +;refused, and SERVE fails to skip. +;If $$SYSDBG is 1, then SERVE accepts all connections but returns in C +;a value which is nonzero if the foreign host ought to be locked out by SYSDBG. + +;Clobbers A, D, T and TT. + +$$CONNECT==1 ;We call CHALSN. + +CHASRV: SYSCAL SSTATU,[MOVEM TT ? MOVEM SYSDBG'] + .LOSE %LSSYS + MOVEI TT,%COLSN + PUSHJ P,CHACN0 ;Start things up + POPJ P, ;Lost +;Listen done. Check host number, return OPN or CLS + CAIE TT,%CSRFC ;Have we an RFC to accept? + POPJ P, ;No, something went wrong + SYSCAL PKTIOT,[MOVEI (A) ? MOVEI PKTBUF] ;Get the RFC packet + .LOSE %LSSYS + LDB B,[$CPKSA+PKTBUF] ;Get source host +IFN $$HST3,IOR B,[NW%CHS] +.ELSE TLO B,NW%CHS_9 ;Including network number +IFE $$SYSDBG,[ ;Reject rfc if system down + SKIPL SYSDBG + JRST CHASV1 + MOVEI T,%COCLS ;Return CLS + DPB T,[$CPKOP+PKTBUF] + PUSH P,C + MOVEI C,[ASCIZ/System not up/] + PUSHJ P,CHSTNG + POP P,C + SYSCAL PKTIOT,[MOVEI 1(A) ? MOVEI PKTBUF] + .LOSE %LSSYS + JRST CHASRV ;Try again + +CHASV1: ];$$SYSDBG + MOVEI T,%COOPN ;Return Open + DPB T,[$CPKOP+PKTBUF] + SYSCAL PKTIOT,[MOVEI 1(A) ? MOVEI PKTBUF] + .LOSE %LSSYS +IFN $$SYSDBG,[ + SKIPL C,SYSDBG ;If system being debugged, may disallow + JRST [ SETZ C, ? JRST POPJ1 ] + ;Unlike Arpanet, we don't have selective disallow, just disallow everyone +];$$SYSDBG + JRST POPJ1 +] ;END IFN $$SERVE +];ITS +IFN TNX,[ +];TNX + +IFN $$CONNECT,[ +IFN ITS,[ +;CHAOS NETWORK CONNECT ROUTINE +; +;Call: MOVEI A,chnl ;Input channel number. That+1 is output channel. +; MOVEI B,host ;host number to connect to +; MOVEI C,contact name ;an ASCIZ string +; MOVEI D,window size +; PUSHJ P,NETWRK"CHACON +; lossage ;you may call ANALYZE to get an error message. +; ;If $$ERRHAN is nonzero, we call ANALYZE for you. +; +;Clobbers only T and TT. +; +;CHALSN is the same as CHACON except that it uses LSN instead of RFC. +; B is host number it must be from, or 0 if any host is acceptable. + +.VECTOR PKTBUF(%CPMXW) ;Buffer used by Open, Close, and Analyze + +CHACON: +$$LOG, LOG CHACON,[B,C] + MOVEI TT,%CORFC + PUSHJ P,CHACN0 ;Start things up + POPJ P, ;Lost + CAIE TT,%CSOPN + JRST CHACNL ;Started but didn't get open + JRST POPJ1 ;CHACON done + +CHACN0: SETZM PKTBUF + MOVE T,[PKTBUF,,PKTBUF+1] + BLT T,PKTBUF+%CPMXW-1 ;For extra luck, clear the packet buffer + DPB B,[$CPKDA+PKTBUF] ;Destination host + DPB TT,[$CPKOP+PKTBUF] + PUSHJ P,CHSTNG ;Store string from C + SYSCAL CHAOSO,[MOVEI (A) ? MOVEI 1(A) ? D] ;Assign Chaos index + JRST CHACNL + SYSCAL PKTIOT,[MOVEI 1(A) ? MOVEI PKTBUF] ;Send RFC or LSN + .LOSE %LSFIL + MOVEI TT,$$CHATO ;15-second timeout + SKIPE DEBUG + MOVSI TT,177777 ;Or infinite, in debug mode + LDB T,[$CPKOP+PKTBUF] + CAIE T,%COLSN ;Get the boring state + SKIPA T,[%CSRFS] + MOVEI T,%CSLSN + SYSCAL NETBLK,[MOVEI 1(A) ? T ? TT ? MOVEM TT] ;Await completion of connection + JRST CHACNL + JRST POPJ1 ;Return to second half + +CHALSN: MOVEI TT,%COLSN + PUSHJ P,CHACN0 ;Start things up + POPJ P, ;Lost +;Listen done. Check host number, return OPN or CLS + CAIE TT,%CSRFC ;Should be RFC into LSN + JRST CHACNL + SYSCAL PKTIOT,[MOVEI (A) ? MOVEI PKTBUF] ;Get the RFC packet + .LOSE %LSFIL + LDB T,[$CPKSA+PKTBUF] ;Check source host + CAIE T,(B) ;Not looking at network number + JUMPN B,CHALS2 ;Jump if doesn't match + MOVEI T,%COOPN ;Matches or we don't care, return open + DPB T,[$CPKOP+PKTBUF] + SYSCAL PKTIOT,[MOVEI 1(A) ? MOVEI PKTBUF] + .LOSE %LSFIL + JRST POPJ1 + +CHALS2: MOVEI T,%COCLS ;Return CLS + DPB T,[$CPKOP+PKTBUF] + PUSH P,C + MOVEI C,[ASCIZ/You are the wrong host./] + PUSHJ P,CHSTNG + POP P,C + SYSCAL PKTIOT,[MOVEI 1(A) ? MOVEI PKTBUF] + .LOSE %LSFIL + JRST CHALSN ;Try again + +CHACNL: ;CHACON or CHALSN lost +IFN $$ERRHAN, JRST ANALNS +.ELSE POPJ P, + +;Store string from C into PKTBUF. Bash T, TT +CHSTNG: PUSH P,B + PUSH P,C + MOVE B,[440800,,PKTBUF+%CPKDT] + MOVEI TT,0 + HRLI C,440700 +CHSTG1: ILDB T,C + JUMPE T,CHSTG2 + IDPB T,B + CAIGE TT,%CPMXC-1 + AOJA TT,CHSTG1 +CHSTG2: DPB TT,[$CPKNB+PKTBUF] + POP P,C + POP P,B + POPJ P, +] ;END IFN $$CONNECT +];ITS +IFN TNX,[ +];TNX + +IFN $$SIMPLE,[ +IFN ITS,[ +; CHASMP +; A - channel pair +; B - foreign host +; C - pointer to asciz string of contact name and arguments (if any) +; D - aobjn pointer to buffer in which answer is returned as asciz string +; Returns: +; non-skip failed to get response, or error response (you can call ANALYZE) +; skip once CLS response, asciz string in D's buffer +; skip twice ANS response, asciz string in D's buffer + +CHASMP: PUSH P,D + MOVEI D,5 ;Meaningless window size + MOVEI TT,%CORFC + PUSHJ P,CHACN0 ;Start things up + JRST CHASM9 ;Lose + CAIN TT,%CSCLS + SYSCAL PKTIOT,[MOVEI (A) ? MOVEI PKTBUF] ;Get the ANS/CLS packet + JRST CHASM9 ;Didn't get proper response + LDB TT,[$CPKOP+PKTBUF] + CAIN TT,%COANS + AOSA -1(P) ;Skip twice + CAIN TT,%COCLS + AOSA -1(P) ;Skip once + JRST CHASM9 ;Skip no times (shouldn't get here usually) + PUSH P,C + HLRE C,-1(P) ;Get minus number of words + IMUL C,[-5] + SUBI C,1 ;Number of characters not counting terminator + MOVE D,-1(P) + HRLI D,440700 + MOVE TT,[440800,,PKTBUF+%CPKDT] + LDB T,[$CPKNB+PKTBUF] + CAMGE T,C + MOVE C,T +CHASM1: ILDB T,TT + IDPB T,D + SOJG C,CHASM1 + IDPB C,D + POP P,C +CHASM9: POP P,D + POPJ P, +] ;END IFN $$SIMPLE +];ITS +IFN TNX,[ +];TNX +] ;END IFN $$CHAOS + +IFN $$TCP,[ +IFN $$SERVE,[ + +;Call: MOVEI A,chnl ;Input channel number. That+1 is output channel. +; MOVEI B,port# +; PUSHJ P,NETWRK"TCPSRV +; lossage ;you may call ANALYZE to get an error message. +; ;If $$ERRHAN is nonzero, we call ANALYZE for you. +; +;Returns in B the number of the foreign host. +; +;If $$SYSDBG is 0, then connections from all hosts are +;refused, and SERVE fails to skip. +;If $$SYSDBG is 1, then SERVE accepts all connections but returns in C +;a value which is nonzero if the foreign host ought to be locked out by SYSDBG. + +;Clobbers A, D, T and TT. + +$$CONNECT==1 ;just for TCPCNL + +TCPSRV: SYSCAL SSTATU,[MOVEM TT ? MOVEM SYSDBG'] + .LOSE %LSSYS + SYSCAL TCPOPN,[MOVEI (A) ? MOVEI 1(A) ? B + [-1] ? [-1]] ; Wild fgn port and host. + JRST TCPCNL ; Bah, failed for some reason. + MOVEI TT,$$TCPTO ;15-second timeout + SKIPE DEBUG + MOVSI TT,177777 ;Or infinite, in debug mode + MOVEI T,%NSLSN ; Initial state to hang on. +TCPSV1: SYSCAL NETBLK,[MOVEI 1(A) ? T ? TT ? MOVEM T ? MOVEM TT] + .LOSE %LSSYS ; Gack? + JUMPLE TT,TCPCNL ; Exit if timed out + CAIN T,%NSRFC ; If in SYN-RECEIVED state + JRST TCPSV1 ; then it's OK to keep waiting. + CAIE T,%NSOPN ; Else should be open now. + CAIN T,%NSRFN + CAIA + JRST TCPCNL ; Aw, phooie. + + ; TCP connection open now. + SYSCAL RFNAME,[MOVEI 1(A) ? MOVEM T + MOVEM T ; Local port # (should be = ICPSOC) + MOVEM T ; Foreign port # + MOVEM B]; Foreign host # + .LOSE %LSSYS ; Gack? +IFE $$SYSDBG,[ ;Reject rfc if system down + SKIPL SYSDBG + JRST TCPSV2 + ;I don't know how to do this right. Just send string and close + MOVE T,[440700,,[ASCIZ/System not up/]] + MOVEI TT,13. + SYSCAL SIOT,[MOVEI 1(A) ? T ? TT] + JFCL + SYSCAL CLOSE,[MOVEI (A)] + .LOSE %LSSYS + SYSCAL CLOSE,[MOVEI 1(A)] + .LOSE %LSSYS + JRST TCPSRV ;Try again + +TCPSV2: ];$$SYSDBG +IFN $$SYSDBG,[ + SKIPL C,SYSDBG ;If system being debugged, may disallow + JRST [ SETZ C, ? JRST POPJ1 ] + ;Unlike Arpanet, we don't have selective disallow, just disallow everyone +];$$SYSDBG + JRST POPJ1 +] ;END IFN $$SERVE + +IFN $$CONNECT,[ + +;TCP CONNECT ROUTINE +; +;Call: MOVEI A,chnl ;Input channel number. That+1 is output channel. +; MOVEI B,host ;host number to connect to +; MOVEI C,foreign port ;you don't get to pick the local port +; PUSHJ P,NETWRK"TCPCON +; lossage ;you may call ANALYZE to get an error message. +; ;If $$ERRHAN is nonzero, we call ANALYZE for you. +; +;Clobbers only T and TT. + +TCPCON: +$$LOG, LOG TCPCON,[B,C] + MOVEI T,1(A) ;Output channel + .CALL [ SETZ ? 'TCPOPN' ? A ? T ? [-1] ? C ? SETZ B ] + JRST TCPCNL ;Didn't even start trying + MOVEI TT,$$TCPTO ;15-second timeout + SKIPE DEBUG + MOVSI TT,177777 ;Or infinite, in debug mode + .CALL [ SETZ ? 'NETBLK' ? MOVEI 1(A) ? MOVEI %NSRFS ? TT + SETZM T ] ;T gets state it went into + .LOSE %LSSYS + CAIE T,%NSOPN ;Good state? + CAIN T,%NSRFN + JRST POPJ1 ;Success +TCPCNL: ;Timed out or failed +IFN $$ERRHAN, JRST ANALNS +.ELSE POPJ P, +];$$CONNECT +];$$TCP + +IFN $$ANALYZE*ITS,[ + +; Network error analysis. + +;Call: MOVEI A,pin ;channel number that is losing +; PUSHJ P,ANALYZE +; .VALUE ;always skip-returns +; +;Clobbers only T and TT. Uses the PUTCHR routine to type out its messages. +;Does not type a crlf after the message. + +.VECTOR WHYINT(5) ;Cruft returned from WHYINT + +ANALYZE: + AOS (P) + PUSH P,B + PUSH P,C +ANALN1: SYSCAL USRVAR,[MOVEI %JSELF ? MOVEI .RIOC(A) ? MOVEM T ] ;Channel open? + .LOSE %LSSYS + JUMPE T,ANALN2 ;No, don't clobber error code with WHYINT + SYSCAL WHYINT,[A ? MOVEM WHYINT ;Get device type + MOVEM WHYINT+1 ? MOVEM WHYINT+2 ? MOVEM WHYINT+3 + MOVEM WHYINT+4 ] + .LOSE %LSFIL + MOVE T,WHYINT ; Get device type +IFN $$TCP\$$ARPA,[ + CAIE T,%WYNET + CAIN T,%WYTCP + JRST ANAL1 ; Go analyze NCP/TCP channel. +];$$TCP\$$ARPA +IFN $$CHAOS,[ + CAIN T,%WYCHA + JRST ANLCHA ;Chaos net channel open, further info available +];$$CHAOS +ANALN2: SYSCAL USRVAR,[MOVEI %JSELF ? MOVEI .RIOS(A) ? MOVEM T] ;Get I/O status wd for channel + .LOSE %LSSYS + LDB TT,[220600,,T] ;only the open-loss code is available + CAIN TT,%EFLDV ;Device full (this one applies to both Arpanet & Chaos net) + JRST [ JSP TT,SPEAK + ASCIZ \All sockets in use.\ ] + CAIN TT,%ENRDV ;Device not ready + JRST [ JSP TT,SPEAK + ASCIZ \Network down.\ ] +IFN $$ARPA,[ + CAIE TT,%ENAPP ;Other end of pipeline gone, or + CAIN TT,%ENSDR ;No such directory + JRST [ ;Host is down, say why. + MOVE T,ARPHST ;Go print status for last host hacked, is probably right one + JRST ANALC1 ] ;Unfortunately, channel not open, can't get right host + CAIN TT,%ESCO ;Self-contradictory open + JRST [ JSP TT,SPEAK + ASCIZ \Connection cannot be opened because of inconsistent byte sizes.\ ] +];$$ARPA + SYSCAL IOPUSH,[A] ;Some other error - get ITS error message + .LOSE %LSSYS + .CALL [ SETZ + SIXBIT/OPEN/ + MOVEI (A) ;here we rely on .UAI=0 + ['ERR',,] + MOVEI 3 ;Status from T + SETZ T ] + .LOSE %LSFIL + MOVEI TT,[ASCIZ\? Internal error - \] + PUSHJ P,ZTYPE +ANAL0: SYSCAL IOT,[MOVEI (A) ? MOVEM T] ;copy error message to output device + .LOSE %LSSYS + CAIGE T,40 + JRST ANALYX + PUSHJ P,PUTCHR + JRST ANAL0 + +ANALYX: SYSCAL IOPOP,[A] + .LOSE %LSSYS +ANALX: POP P,C + POP P,B + POPJ P, + +IFN $$TCP\$$ARPA,[ +; Arpanet channel still open - further information available + +ANAL1: HRRZ TT,WHYINT+1 ;get socket state + JUMPE TT,ANALC .SEE %NSCLS ;connection closed +IFN $$TCP,[ + CAIN T,%WYTCP + JRST ANAL20 ; Report TCP channel state +] ;$$TCP + CAIN TT,%NSRFS ;state is %NSRFS => we must have timed out at CONFIN. + JRST [ JSP TT,SPEAK + ASCIZ /Timed-out while awaiting response to opening of connection./ ] + CAIN TT,%NSLSN ;same but listening rather than rfc'ing + JRST [ JSP TT,SPEAK + ASCIZ/Timed-out while listening for request to open connection./ ] + JRST ANAL50 ; Give up, complain about illegal state + +IFN $$TCP,[ +ANAL20: CAILE TT,%NTINP + JRST ANAL50 ; State too big + PUSH P,TCPSTB(TT) ; Get state message + MOVEI TT,[ASCIZ /Connection /] + PUSHJ P,ZTYPE + POP P,TT + JRST SPEAK + +TCPSTB: OFFSET -. +%NTCLS:: [ASCIZ /closed./] +%NTLSN:: [ASCIZ /listening./] +%NTSYR:: [ASCIZ /wedged, SYN rcvd but not acked./] +%NTCLU:: [ASCIZ /being closed by foreign host./] +%NTSYN:: [ASCIZ /waiting for response to SYN./] +%NTOPN:: [ASCIZ /open./] +%NTWRT:: [ASCIZ /open, output buffer full./] +%NTCLX:: [ASCIZ /being closed by user./] +%NTCLI:: [ASCIZ /closed, input still available./] +%NTINP:: [ASCIZ /open, input available./] + OFFSET 0 +] ;$$TCP +ANAL50: PUSH P,TT + MOVEI TT,[ASCIZ\? Socket entered illegal state #\] + PUSHJ P,ZTYPE + LDB T,[030300,,(P)] + SKIPE T + PUSHJ P,[ ADDI T,"0" ? JRST PUTCHR ] + POP P,T + ANDI T,7 + ADDI T,"0" + PUSHJ P,PUTCHR + JRST ANALX +];$$TCP\$$ARPA + +SPEAK: PUSHJ P,ZTYPE ;send message from TT + JRST ANALX ; and return + +IFN $$TCP\$$ARPA,[ + +;Say why connection was closed +ANALC: SYSCAL RFNAME,[MOVEI (A) ? MOVEM T + MOVEM T ? MOVEM T ; Local port, fgn port + MOVEM T ] ; Fgn host (NCP: 1.1-1.9) + .LOSE %LSSYS + HRRZ TT,WHYINT+3 ; Get close reason + CAIL TT,LCLSTB + SETO TT, + MOVE TT,CLSTAB(TT) ;get asciz close reason + PUSH P,T ;save host number + PUSH P,TT + PUSHJ P,ZTYPE + POP P,TT + POP P,T + JUMPGE TT,ANALX ;return if host is up + MOVE TT,WHYINT + CAIN TT,%WYTCP ; If TCP, must do further checking + JRST [ GETNET TT,T ; Get network number + CAME TT,[NW%ARP] ; Can only get status for arpanet sites + JRST ANALX ; Sorry, no can do. + JRST .+1] ; Aha, try NETHST call. + + PUSHJ P,CRLF ;CRLF between down message and down reason +ANALC1: SYSCAL NETHST,[T ? MOVEM T] ;get information about why host down + .LOSE %LSSYS + MOVE B,T + TRZ T,777760 ;RH gets just reason down + TLNE T,2000 ;skip if down + SETO T, + MOVE TT,DEDTAB(T) ;get asciz string describing situation + PUSHJ P,ZTYPE +IFE $$UPTM,JRST ANALX +IFN $$UPTM,JRST ANALTM + +IFN $$UPTM,[ + +;OPTIONALLY, SAY WHEN THE IMP THINKS THE HOST WILL BE BACK UP. +ANALTM: ANDI B,177760 ; get time back + JUMPE B,ANALX ; flush if nothing + CAIN B,177740 ; -2 means unknown future time + JRST ANALX ; There isn't anything useful to say about this. + MOVEI TT,[ASCIZ / Host is expected back up /] + PUSHJ P,ZTYPE + CAIN B,177760 ; -1 means more than a week + JRST [ JSP TT,SPEAK + ASCIZ /over a week from now./ ] + LDB T,[150300,,B] ; get day of week + LDB TT,[100500,,B] ; get hours time + SUBI TT,5 ; EST/GMT offset + PUSH P,B + .RYEAR B, ; get time info + TLNE B,100000 ; daylight losing time? + AOSL TT ; yes, go ahead an hour + JUMPGE TT,NODAY ; easy way out + ADDI TT,24. ; move up a day + SOSGE T ; and days back + MOVEI T,6 ; back to Sunday +NODAY: MOVE B,TT ; Save real hours + MOVE TT,DOWTAB(T) ; Get string describing day of week. + PUSHJ P,ZTYPE + MOVEI TT,[ASCIZ / at /] + PUSHJ P,ZTYPE + MOVE T,B ; get hours time + PUSHJ P,2DTYPE + MOVEI T,":" + PUSHJ P,PUTCHR + POP P,B ; Restore original time + LDB T,[040400,,B] ; get minutes/5 + IMULI T,5. ; make into real minutes + PUSHJ P,2DTYPE + MOVEI TT,[ASCIZ/ EST./] + .RYEAR T, + TLNE T,100000 + MOVEI TT,[ASCIZ/ EDT./] + PUSHJ P,ZTYPE + JRST ANALX + +;TYPE NUMBER IN T AS TWO DECIMAL DIGITS. +2DTYPE: IDIVI T,10. ; split high and low order + ADDI T,"0" ; ASCIIify + ADDI TT,"0" ; ASCIIify + PUSH P,TT + PUSHJ P,PUTCHR + POP P,T + JRST PUTCHR + +DOWTAB: [ASCIZ/on Monday/] + [ASCIZ/on Tuesday/] + [ASCIZ/on Wednesday/] + [ASCIZ/on Thursday/] + [ASCIZ/on Friday/] + [ASCIZ/on Saturday/] + [ASCIZ/on Sunday/] + [ASCIZ/on April Fool's day/] + +] ;END IFN $$UPTM +];$$TCP\$$ARPA + +IFN $$CHAOS,[ +;Analyze on chaos channel, still open + +ANLCHA: MOVE TT,WHYINT+1 ;Connection state + CAIE TT,%CSLOS + CAIN TT,%CSCLS + JRST ANLCH1 + CAIE TT,%CSINC + JRST ANLCH0 ;Still open + JSP TT,SPEAK + ASCIZ /Connection broken -- foreign host not communicating./ + +ANLCH0: PUSH P,CHSTTB(TT) + MOVEI TT,[ASCIZ/Timed-out while connection /] + PUSHJ P,ZTYPE + POP P,TT + JRST SPEAK + +CHSTTB: [ASCIZ/closed/] + [ASCIZ/listening/] + [ASCIZ/has received RFC/] + [ASCIZ/trying to get connected/] ;has sent RFC + [ASCIZ/open/] + [ASCIZ/lost/] + [ASCIZ/broken/] + +ANLCH1: PUSH P,CHSTTB(TT) + MOVEI TT,[ASCIZ/Connection /] + PUSHJ P,ZTYPE + POP P,TT + PUSHJ P,ZTYPE + MOVEI TT,[ASCIZ/ -- /] + PUSHJ P,ZTYPE + HLRZ TT,WHYINT+2 ;get number of input packets +ANLCH2: SOJL TT,ANALX ;scan input looking for CLS, LOS + HLRZ T,WHYINT+4 ;Pick up input channel number + SYSCAL PKTIOT,[T ? MOVEI PKTBUF] + .LOSE %LSFIL + LDB T,[$CPKOP+PKTBUF] + CAIE T,%COCLS + CAIN T,%COLOS + SKIPA B,[440800,,PKTBUF+%CPKDT] + JRST ANLCH2 + LDB C,[$CPKNB+PKTBUF] +ANLCH3: SOJL C,ANALX + ILDB T,B + PUSHJ P,PUTCHR + JRST ANLCH3 +];$$CHAOS + +IFN $$ARPA\$$TCP,[ + +; Tables + +;Close Reasons + + [ASCIZ/Illegal close-reason code??/] +CLSTAB: OFFSET -. +%NCNTO::[ASCIZ/Connection never opened??/] +%NCUSR::[ASCIZ/Connection legitimately closed??/] +%NCFRN::[ASCIZ/Connection closed by foreign host./] +%NCRST::[ASCIZ/Connection reset by foreign host./] +%NCDED::400000,,[ASCIZ/Host died./] +%NCINC::400000,,[ASCIZ/Incomplete transmission - foreign host or network died./] +%NCBYT::[ASCIZ/Byte size mismatch??/] +%NCNCP::[ASCIZ/Local Network Control Program reset./] +%NCRFS::[ASCIZ/Request for Connection refused by foreign host./] +LCLSTB::OFFSET 0 + +;Host Dead Reasons + + [ASCIZ/Illegal host-dead code??/] +DEDTAB: [ASCIZ/ Network lossage./] ;0 probably no host-dead-reason returned + [ASCIZ/ Destination Host dead./] ;1 WOULDN'T SAY WHY + [ASCIZ/ Foreign Network Control Program not in operation./] + [ASCIZ/ Destination Host or IMP does not exist./] + [ASCIZ/ Destination Host is initializing its NCP software./] + [ASCIZ/ Destination Host down for scheduled maintenance./] + [ASCIZ/ Destination Host down for scheduled hardware work./] + [ASCIZ/ Destination Host down for scheduled software work./] + [ASCIZ/ Destination Host is in emergency restart./] + [ASCIZ/ Destination Host down due to power failure./] + [ASCIZ/ Destination Host is stopped at a breakpoint./] + [ASCIZ/ Destination Host down due to hardware failure./] + [ASCIZ/ Destination Host is not scheduled to be up./] + [ASCIZ/ (Undefined host-down code 13.)/] + [ASCIZ/ (Undefined host-down code 14.)/] + [ASCIZ/ Destination Host is coming up now./] + +];$$ARPA\$$TCP +];END IFN $$ANALYZE*ITS + +IFN $$CVH,[ +;;;; Utilities - CVH2NA, CVH3NA + +; CVH2NA - Convert network host address in A to HOSTS2 format. +; A/ net address (any format) +; Returns A + +CVH2NA: PUSH P,B + LDB B,[301400,,A] ; Get high 12 bits of net address + CAIGE B,70 ; If less than lowest HOSTS2-fmt value + JUMPN B,CVH2N3 ; then must be HOSTS3, go convert. + CAIL B,1000 ; If any of high 3 bits set, + JRST CVH2N3 ; then it's a HOSTS3 strange-fmt number. + JUMPN B,CVH2N2 + CAILE A,377 ; Zero network, so must be ARPA net + JRST CVH2N1 ; Not just 8 bits, just add net number. + + ; Old-style 8-bit Arpanet host number + LSHC A,-6. + ROT B,6. + DPB B,[112000,,A] +CVH2N1: TLO A,(12_33) + JRST CVH2N9 + + ; Probably HOSTS2 format number +CVH2N2: JRST CVH2N9 ; For now, that's good enough. + + ; HOSTS3 format number, convert it. +CVH2N3: CAIN B,12 ; Arpa net? + JRST [ LSHC A,-16. + ANDI A,377 + ROT B,16. + DPB B,[112000,,A] + TLO A,(12_33) + JRST CVH2N9] + CAIN B,7+ ; Chaos net? + JRST [ ANDI A,177777 ; Yup, fix it up. + TLO A,(7_33) + JRST CVH2N9] + CAIN B,22 ; LCS net? + JRST [ LSHC A,-8. + ANDI A,-1 + LSH A,2 + LSHC A,8. + TLO A,(22_33) + JRST CVH2N9] + + ; Not a known net, but try to do something plausible. + ANDCM A,[-1_24.] ; Preserve low 24 bits + DPB B,[331100,,A] ; put net # into HOSTS2 field. +CVH2N9: POP P,B + POPJ P, +] ;$$CVH + +; CVH3NA - Convert network host address in A to HOSTS3 (Internet) format. +; A/ net address (any format) +; Returns A + +CVH3NA: PUSH P,B + LDB B,[301400,,A] ; Get high 12 bits of net address + CAIGE B,70 ; If less than lowest HOSTS2 value, + JUMPN B,CVH3N3 ; it's already HOSTS3 format! (unless zero) + CAIL B,1000 ; If any of high 3 bits were set, + JRST CVH3N3 ; it must be a HOSTS3 strange-fmt addr. + JUMPN B,CVH3N2 ; If not zero, then must assume HOSTS2 fmt. + + ; Old-format 8-bit Arpanet host number, or HOSTS2 with zero net. +IFE $$ARPA,IFN $$CHAOS, IOR A,[NW%CHS] ? JRST CVH3N3 + CAILE A,377 + JRST CVH3N6 ; If greater than 8 bits, assume HOSTS2, zero net. + LSHC A,-6 ; Put 10 bits spacing between host/imp #s. + LSH B,-<2+8.> + LSHC A,<2+8.+6> + TLO A,(12_24.) ; and add ARPA network number. + JRST CVH3N3 + + ; HOSTS2 format number +CVH3N2: TRZE B,7 ; Zap low 3 bits to ensure correct comparison + JRST CVH3N5 ; If any were set, can't be Chaosnet. + CAIN B,7_3 ; Chaos net? + JRST [ ANDI A,177777 ; Yes, kill all but bottom 16 bits + TLO A,(NE%UNT+<7_24.>) ; Add Chaos net # + JRST CVH3N3] +CVH3N5: CAIN B,12_3 ; Arpa net? +CVH3N6: JRST [ LSHC A,-9. + ANDI A,177777 + ROT B,9. + DPB B,[201000,,A] + TLO A,(12_24.) + JRST CVH3N3] + CAIN B,22_3 ; LCS net? + JRST [ LSHC A,-8. + LSH A,-2 + ANDI A,377 + LSHC A,-8. + TLO A,(22_24.) + JRST CVH3N3] + + ; No match, assume it's HOSTS3. +CVH3N3: POP P,B + POPJ P, + + +$$LOG,[ +;;; Logging - CStacy, 22 October 1984 +;;; +;;; This facility is (originally) so that I can see which users are using +;;; the TELNET and FTP facilities on our machine and to help discover who +;;; is using us as a base in attacking other sites. Maybe ITS should do +;;; some sort of network logging like Multics, but I'll just put it in +;;; this library for now since it isn't clear how generally useful it is +;;; or what functionality we want. + +LOGO==1 ;Channel for log file. +LOGL==2 ;Channel for log file lock-file. + +;;; NOTE: The user could easily become screwed up if we're interrupted. +;;; --We have IOPUSHed channels away from the user without consent. +;;; --We do synchronous file IO behind its back and handle our own errors. +;;; Therefore, LOG processing defers all interrupts. +;;; The LOG stuff is only called before opening and after closing network +;;; channels, and so this should be a first approximation to a safe practice. + +;;; Logfile entries are scattered through the file in sequential order. +;;; They are of variable length. They begin with a unique id number; +;;; The log for a particular job can be threaded from the id. +;;; +;;; An transaction entry looks like: +;;; /BEGIN/ +;;; BEGIN-CODE (id) The 36 bit unique id code for this job. +;;; TIMESTAMP The time of the entry. +;;; OPCODE Sixbit name of the transaction type. +;;; CRUFT WORDS Transaction dependant data. +;;; +;;; +;;; The NETLOG program (source in AR2:CSTACY;NETLOG) can be used to +;;; expand a logfile into an ASCII representation of some or all of the +;;; transactions. +;;; +;;; It is possible to have incomplete records of network usage +;;; in the logfile, since if many things go wrong we abort the +;;; logging procedure rather than waste time being too robust +;;; when the entire facility is supposed to be invisible. + +;;; NETWRK routines may call LOGACT to log some action. +;;; Callers provide any list of cruft they want, the first word +;;; being SIXBIT name of the operation. +;;; Semantics for entries should be documented here for interested +;;; programmers to find out how to decode the log file. +;;; +;;; OPEN: +;;; ANALYZ: ... +;;; + +.SCALAR LOGID ;Our id number in the log file. + +;;; LOGACT - Log some action +;;; A/ number of crufty words on the stack (P) before the funcall. +;;; Smashes no ACs and never skips. +;;; Caller must pop his args back off himself. + +LOGACT: MOVE T,P ;Save current SP here for a moment. + .SUSET [.RPICLR,,TT] ;Read global interrupt defer word. + PUSH P,TT ;Stack it away for restoration. + .SUSET [.SPICLR,,[0]] ;Defer all interrupts. + .IOPUSH LOGO, ;Push the channels we want, + .IOPUSH LOGL, ;hoping the IOPDL doesn't overflow. + PUSH P,A ;Do not smash ACs. + PUSH P,B + PUSH P,C + PUSH P,D + MOVE B,T ;B gets SP to top of LOGACT frame. +LOGA10: PUSHJ P,LOGOPN ;Open log file if needed. + JRST LOGCLS + SYSCAL ACCESS,[%CLIMM,,LOGO ? C] ;Move to EOF. + JRST LOGCLS + SUB B,A ;Point to first arg. + HRLZ A,A + HRR A,B ;A has length,,adr of crufties. +LOGA20: SYSCAL RQDATE,[%CLOUT,,B] + JRST LOGCLS + SKIPE C,LOGID ;If our id has been initialized, + JRST LOGA30 ; go make an entry. + .SUSET [.RUIND,,C] ;Else find our job number. + HRL C,B ;*** This should be more or less unique? ** + MOVEM C,LOGID ;Set our id. +LOGA30: MOVE T,[444400,,[SIXBIT /BEGIN/]] + MOVEI TT,1 + SYSCAL SIOT,[%CLIMM,,LOGO ? T ? TT] ;Write entry marker. + JRST LOGCLS + MOVE T,[444400,,B] + MOVEI TT,2 + SYSCAL SIOT,[%CLIMM,,LOGO ? T ? TT] ;Write timestamp and id. + JRST LOGCLS + .SUSET [.RUNAME,,B] + .SUSET [.RJNAME,,C] + MOVE T,[444400,,B] + MOVEI TT,2 + SYSCAL SIOT,[%CLIMM,,LOGO ? T ? TT] ;UNAME, JNAME. + CAIA +LOGA40: HRRZ T,A ;Get ptr to stacked args. + HRLI T,444400 ;Make BP. + HLRZ TT,A ;Get length. + SYSCAL SIOT,[%CLIMM,,LOGO ? T ? TT] ;Write opcode, crufties. + JRST LOGCLS +LOGCLS: .CLOSE LOGO, + .CLOSE LOGL, + .IOPOP LOGL, + .IOPOP LOGO, + POP P,D + POP P,C + POP P,B + POP P,A + POP P,T ;Probably -1 (no global deferment). + .SUSET [.SPICLR,,T] ;Restore interrupt defer state. + POPJ P, ;All done. + + +;;; LOGOPN - Seize the logfile lock, and open the logfile for writing. +;;; Uses LOGL and LOGO file channels, and skips on success. +;;; Returns length of the database in C, does not smash other ACs. +;;; Notes: +;;; o If the lock file is missing LOGOPN will re-create it. +;;; o If the logfile itself is missing, we just fail. + +LOGMLT==6 ;Maximum # attempts to make trying to seize the lock. + +LOGOPN: PUSH P,A + PUSH P,B + SETZ B, ;Count of locking attempts in B. +LOGLOK: SYSCAL OPEN,[%CLBIT,,.BIO\%DOWOV ? %CLIMM,,LOGL + [SIXBIT /DSK/] + [SIXBIT /NETLOG/] + [SIXBIT /LOCK/] + [SIXBIT /SPACY/]] + CAIA + JRST LOGLKD ;Got it! + CAIL B,LOGMLT ;Else if we have exceeded the retry maximum + JRST LOGLKF ; Fail. + .STATUS LOGL,A ;Let's see why the open failed. + LDB A,[220600,,A] ;Get error code. + CAIN A,%ENAFL ;If someone else has the lock + JRST [ MOVEI T,30. ; Sleep for one second. + .SLEEP T, ; (They should give it up soon.) + AOS B ; Keep count of attempts to seize lock. + JRST LOGLOK ] ; Try,try again. + CAIE A,%ENSFL ;Hmmm....Maybe the lock file is missing? + JRST LOGLKF ; Nope - some random lossage. + SYSCAL OPEN,[%CLBIT,,.UAO ? %CLIMM,,LOGL ;Re-create it. + [SIXBIT /DSK/] + [SIXBIT /NETLOG/] + [SIXBIT /LOCK/] + [SIXBIT /SPACY/]] + JRST LOGLKF ; Fail if could not create lock. + .CLOSE LOGL, ;Else close file + JRST LOGLOK ;and try to seize it again. +LOGLKD: SYSCAL OPEN,[%CLBIT,,.BII ? %CLIMM,,LOGO + [SIXBIT /DSK/] + [SIXBIT /NETLOG/] + [SIXBIT / DATA/] + [SIXBIT /SPACY/]] + JRST LOGLKF + SYSCAL FILLEN,[%CLIMM,,LOGO ? %CLOUT,,C] + JRST LOGLKF + .CLOSE LOGO, ;Protocol says no lock competition here. + SYSCAL OPEN,[%CLBIT,,%DOWOV+.UIO ? %CLIMM,,LOGO + [SIXBIT /DSK/] + [SIXBIT /NETLOG/] + [SIXBIT / DATA/] + [SIXBIT /SPACY/]] + CAIA ; Huh? We opened it a moment ago??? + AOS -2(P) ;Skip return if won. +LOGLKF: POP P,B + POP P,A + POPJ P, + + +];$$LOG + + +.qmtch=qmtch ;set this back to the value the user gave it + +.END NETWRK diff --git a/src/syseng/pft.149 b/src/syseng/pft.149 new file mode 100755 index 00000000..fa212424 --- /dev/null +++ b/src/syseng/pft.149 @@ -0,0 +1,3678 @@ +;;;-*-Midas-*- + +TITLE PFTHMG DRAGON II + +define setf text,flg +ifdef flg,.stop +.tag foobar +printc "text +flg=" +.ttymac flag +.ttyflg==.ttyflg+1 +printx/flag +/ +.ttyflg==.ttyflg-1 +ifse flag,YES,flg==1 +ifse flag,NO,flg==0 +ifse flag,Y,flg==1 +ifse flag,N,flg==0 +ifndef flg,flg==flag +termin +ifndef flg,.go foobar +termin + +setf [Macsyma and decimal time features for MC KL10]$$mcp +;setf [Puff internal stats collection (say yes)]$$stat + +;$$MCP==1 ;non-zero if for MC +$$STAT==1 ;non-zero for PUFF internal stats collection + +A=1 +B=2 +C=3 +D=4 +E=5 +T=6 +TT=7 +H=10 +I=11 +J=12 +Q=13 +R=14 +P=17 + +ERRCH==0 +CLICH==1 +DMPCH==2 +maxch==3 +batusr==4 ;See BATCH +batdsk==5 ;Same Bat time, same Bat channel! +INCH=15 +OUCH=16 + + +define syscal oper,args + .call [setz ? sixbit /oper/ ? args ((setz))] termin + +busrc==100000 ;user control bit in USTP + +EDITF: 0 ;NONZERO => WAITING FOR EDITING +IFN EDITF-100, .ERR EDITF MUST BE LOCATION 100 + +SNAME: sixbit /DRAGON/ ;DIRECTORY TO USE +LOTSNM: sixbit /CHANNA/ ;DIRECTORY FOR LOGOUT TIMES FILE +MALSNM: sixbit /.MAIL./ ;DIRECTORY FOR SENDING MAIL + +DEBUG: -1 ;NONZERO => EXTRA CHECKS, .VALUES, ETC. +FIXIND: 0 ;NONZERO => FIX INDENTATION TO STANDARD VALUES + +PDL: -120,,. + BLOCK 122 + +DEFINE INSIRP INS,VALS + IRPS VAL,,[VALS] + INS,VAL + TERMIN +TERMIN + +ZZ==. + LOC 40 +FORTY: 0 + JSR UUOH + -intlen,,TSINT + LOC ZZ + +;UUOS + +WCHI=1000,, ;WRITE-CHAR-IMMEDIATE +XBUGCH=62000,, ;BUGCHK MACRO - MUST BE MUUO SO NO CLOBBER JPC +XCLBFI=3000,, ;CLBFIL MACRO + +;Give bug message if debugging, and continue +DEFINE BUGCHK MESS/ + XBUGCH [ASCIZ:MESS + +] +TERMIN + +;Give clobbered file message, pop AC times, and jump to GVLFLS to flush rest of line. +DEFINE CLBFIL AC,MESS/ + XCLBFI AC,[ASCIZMESS] +TERMIN + +SUBTTL How it works + +;Accounting information is saved in the DRAGON HOARD file, which is a printable +;ascii file. At the end of the month, this file becomes the monthly report, and +;a new file is started by zeroing all the useages. + +;Accounting information is obtained from the system by looking for "dmn-push" +;messages. The system has a circular buffer which can hold several of these +;messages. When it is idle, the daemon hangs waiting for the count of the +;number of messages pushed to change. It then copies out the messages. +;While it is updating the file, the daemon also checks the dmn-push buffer +;every 1/2 second to try to avoid missing any messages. +;The system pushes these messages when a user logs in or out, and when +;a job tree's name changes e.g. due to detach or attach. In future it may +;also do it spontaneously every fifteen minutes or so to keep the +;accounting up to date. + +;The daemon generates two tables from the dmn-push messages. The logged-in +;tree table has an entry for each job tree that it saw log in to the system. +;The table is indexed by the user-index of the top-level job of the tree. +;This table simply remembers the information from the login message until +;logout time. The cruft table is a sequence of "pieces of cruft." Each +;piece of cruft contains the accounting information for one user session. +;When it comes time to update the accounting file, the pieces of cruft +;are matched against the accounting entries. When a match occurs, the +;usage in the piece of cruft is added to the usage in the accounting file +;for that user. + +;Editing the accounting file. +;It is necessary to lock out updates of the file while it is being +;edited. The TS GEORGE program does this. The dragon remembers any +;dmn-push messages that happen while updating is locked out, so no +;information is lost. GEORGE should also be run just before shooting down +;the dragon to put up a new one, to insure that the file gets updated. + +;The format of the accounting file is as follows: +;It is processed a line at a time. +;A line that begins with white space (actually, space or any control character) +;is a comment, which is not processed by this program. This is used to insert +;headings, page throws (^L), etc. + +;Various special markers are indicated by a whole mess of dashes surrounding +;a keyword. The following keywords exist: +; TOTALS - the next line is for the "TOTALS" user whose usage is the sum of all +; the usage in the file. +; PAGE SUBTOTALS - the next line is for the "TOTALS" user whose usage +; is the sum of all the usage on the same page. +; RANDOMS - the remainder of the page containing this line is for +; "random users". Users not otherwise accounted for +; will be automatically inserted at the bottom of the page. +; Random users who don't log in for a month will be automatically +; deleted. + + +;^L is considered to separate pages. The only difference this makes is +;that "page subtotals" are reset by ^L. Also, ^L ends the randoms section. + +;All other lines are accounting entries. Each accounting entry starts +;with a uname spec, which says what user or set of users will be accounted +;for on this line. It can be further narrowed down through the use of +;JOB, ACCT, and/or HOURS specs. (See below.) The remainder of the line +;contains usage informations, separated by spaces and tabs. These are, in +;order from left to right: the connect-time, the run-time, the swap-in count, +;the logout-date, and the logout-time. Times are in the form dd!hh:mm:ss. +;The swap-in count is just a decimal number. The logout date is in the +;form yy.mm.dd. + +;The uname, job, and acct specs are, in the simplest case, just a sixbit +;name. Legal characters are letters (A-Z and a-z), numbers (0-9), +;underscore (_), and dot (.). +;If any other character is required it should be preceded by a slash (/). +;It is also possible to make a spec that matches a class of names, by use +;of the wild-card characters star (*) and sharp (#). Sharp matches any +;numeric digit. Star matches any character (even space). As a special +;case, a spec consisting of just a star matches anything (normally it would +;just match any one-character name.) + +;The uname spec is matched against the XUNAME (what the user logged in as.) +;The job spec, which is optional and written as "JOB=spec", matches against +;the JNAME of the top-level job. This could be used to separate HACTRNs +;from HACTROs, account separately for job-device jobs ("JOB=JOB.##"), or +;hack daemons. The account spec, which is optional and written as "ACCT=spec", +;matches against the account-name logged in to. [There is currently no +;way for a user to log in to an account name, however.] This is used by +;users who want to split up their usage into several categories. +;The hours spec, which is optional and written as "HOURS=m-n", is used +;to account only for usage between certain hours (currently, it goes +;by the time of login.) E.g. "HOURS=9-5". + +;When initially setting up a file, it is necessary to list all the +;users on the system who should be accounted for, dividing them up +;into pages by groups. Then there should be a page containing just +;-randoms-, and finally a page starting with -totals-, and containing +;a line TOTALS 0.0 0.0 0 0.0 0.0 76.08.01 on MC or +;a line TOTALS 0 0 0 76.08.01 00:00:00 +;(or whatever date is appropriate.) +;If special jobnames, (e.g. job devices) or daemons are to be accounted +;for, they should go at the front. + +;The following files are used by this program: +; +; DRAGON HOARD current accounting file +; DRAGON SAVE previous accounting file +; DRAGON YESTER yesterday's accounting file +; _DRGN_ BUFFER temporary name for output file +; month REPORT completed accounting file for that month +; LOGOUT TIMES old style logout-times file. +; +; It also sends mail to MAGIC-DRAGON-KEEPER and to the last +; person who edited the accounting file if it runs into +; any problems. + +;blah blah + +SUBTTL Program starts here + +GO: .CLOSE 1, + .SUSET [.RSUPPRO,,T] + JUMPGE T,GO1 ;I prefer GO1, changing the directory to ZZ + SETZM DEBUG ;top level => running as daemon + .SUSET [.SXUNAME,,['PFTHMG]] + .SUSET [.SXJNAME,,['DRAGON]] + .SUSET [.SUNAME,,['PFTHMG]] ;UNAME first since TARAKA DRAGON may exist + .SUSET [.SJNAME,,['DRAGON]] + .suset [.shsname,,['DRAGON]] ; for the sake of file authors + JRST GO1 + +GO0: SETZM SNAME ;use debugger's directory. + SETZM LOTSNM +GO1: MOVE P,PDL +GO2: .RDATIM T, ;Wait until ITS thinks it knows the time + IOR T,TT + JUMPGE T,GO3 + MOVEI T,5*30. + .SLEEP T, + JRST GO2 + +GO3: .suset [.ruind,,RUIND] + MOVE T,[SQUOZE 0,LIOBLK] + .EVAL T, + .LOSE + HRLOI T,-1(T) + EQVI T,SYCORE_-10. + SETZ TT, + .CALL [ SETZ ;Map in system core + 'CORBLK + MOVEI %CBRED+%CBNDR + MOVEI %JSELF + MOVE T + MOVEI %JSABS + SETZ TT ] + .LOSE 1000 + IRPS SYM,RELOC,[DMNBC+DMNBD+DMNBF+DMNBFE+DMNBEL DEDTIM+USRHI+LUBLK + UNAME#XUNAME#JNAME#USTP#UTRNTM#USIPRQ#TRUNTM#TSIPRQ# + SUPPRO#TIME+SYSMPT+SYSMLNG SYSMBF+] + MOVE T,[SQUOZE 0,SYM] ;Evaluate necessary system symbols + .EVAL T, + .LOSE + IFSE RELOC,+, ADDI T,SYCORE ;reloc address to system core + IFSE RELOC,#, ADD T,[SYCORE(R)] ;also index by user index in R + MOVEM T,SYM + TERMIN + MOVE T,DMNBFE + SUB T,DMNBF + IDIV T,DMNBEL + MOVEM T,DMNBSZ +IFN $$MCP, pushj p,maxget ;get a page of MACSYMA + + ;; Don't set %OPLIV until we are fairly certain we will live + .SUSET [.ROPTION,,T] + TLO T,%opopc+%opliv+%opint + .SUSET [.SOPTION,,T] + move t,[%rlfls\%rlset,,rltinv] + .realt t, ;give ourself periodic interrupts + JRST IDLE ;Go enter idle loop + +SUBTTL UUO Handler + +UUOH: 0 ;PC stored here + PUSH P,UUOH ;this must be first instruction, see TSINT + PUSH P,T ;UUOs shouldn't clobber any ACs. + LDB T,[331100,,FORTY] + CAIN T,WCHI_-33 + JRST UWCHI + CAIN T,XCLBFI_-33 + JRST UCLBFI + CAIE T,XBUGCH_-33 + .VALUE + .SUSET [.RJPC,,BUGJPC] + JRST UBUGCH + +UWCHI: HRRZ T,FORTY + PUSHJ P,WCH +UUORET: POP P,T + POPJ P, + +;BUGCHK message in debug mode returns to DDT, in non-debug PDUMPs and continues +UBUGCH: SKIPE DEBUG + JRST UBUGC1 + MOVEM 0,BUGACS ;saves ACs (already saved JPC) + MOVE 0,[1,,BUGACS+1] + BLT 0,BUGACS+17 + MOVE 0,BUGACS + .CALL [ SETZ ;save core image + SIXBIT/OPEN/ + [.UIO,,DMPCH] + ['DSK,,] + ['DRAGON] + [SIXBIT/>/] + SETZ [SIXBIT/CRASH/] ] + JRST UUORET ;tough noogies, more important to keep running + SETZ T, + .CALL [ SETZ + SIXBIT/PDUMP/ + MOVEI %JSELF + MOVEI DMPCH + SETZ T ] + JRST UUORET ;tough noogies, more important to keep running + .IOT DMPCH,[JUMPA BUGHAK] + .IOT DMPCH,[JUMPA BUGHAK] + .CLOSE DMPCH, +UBUGCX: JRST UUORET + +BUGHAK: .SUSET [.SJPC,,BUGJPC] ;here restore state so can look at dump + MOVSI 17,BUGACS + BLT 17,17 + .VALUE [ASCIZ\:SL CHANNA;RAKASH PFTHMG +P\] +UBUGC1: POP P,T + .VALUE @FORTY + POPJ P, + +;CLBFIL message in debug mode returns to DDT, in non-debug mode generates mail. +UCLBFI: SKIPE DEBUG + .VALUE [ASCIZ\: CLBFIL  +\] + AOS C,NERRS ;save message and line number in buffer + CAILE C,LERRBF + JRST UCLBF2 + SOS C + HRRZ T,FORTY + MOVEM T,ERRBFZ(C) + MOVE T,LINENO + MOVEM T,ERRBFL(C) + MOVE T,UNAMEA + MOVEM T,ERRBFA(C) + MOVE T,UNAMEB + MOVEM T,ERRBFB(C) + MOVE T,UNAMEC + MOVEM T,ERRBFC(C) +UCLBF2: LDB T,[270400,,FORTY] ;flush pdl + CAIN T,17 + JRST UUORET + ADDI T,2 + HRLS T + SUB P,T + JRST GVLFL1 ;flush rest of input line + +SUBTTL Routines to gobble dmn-push messages + +;Procedure to gobble any dmn-push messages available from the system. +;Clobbers pretty much all ACs. + +DMNPOP: MOVE Q,LDMNBD ;last message processed + CAML Q,@DMNBD + POPJ P, ;buffer empty + ADD Q,DMNBSZ + CAML Q,@DMNBC + JRST DMNPO1 ;jump if haven't missed any +;Following 2 lines commented out. We're never going to get rid of +;these and I'm tired of deleting the crash files. 11/30/77 +; SKIPE LDMNBD ;if just started up, mumble this always happens +; BUGCHK Missed dmn-push message. + MOVE Q,@DMNBC ;get as many as we can + SUB Q,DMNBSZ + MOVEM Q,LDMNBD +DMNPO1: AOS Q,LDMNBD ;take next one after previous + SUBI Q,1 ;fudge (DMNBD=1 after msg 0 pushed). + IDIV Q,DMNBSZ ;mod size of buffer + MOVE Q,R + IMUL Q,DMNBEL + ADD Q,DMNBF ;now Q -> the dmn-push message + HRLZ T,Q ;save the message in case of a BUGCHK + HRRI T,BUGMSG + BLT T,BUGMSG+7 + MOVE T,LI.IDX(Q) ;figure out what type of message it is + TLNE T,LI%COD + JRST DMNPO2 + TLNE T,LO%COD + JRST DMNPO3 + BUGCHK Unknown dmn-push message. + JRST DMNPOP ;try for more messages + +DMNPO2: PUSHJ P,LOGIN + JRST DMNPOP ;try for more messages + +DMNPO3: PUSHJ P,LOGOUT + JRST DMNPOP ;try for more messages + +;Procedure to process dmn-push message for log in. +;Q -> the message. The logged-in tree table is updated. +;Uses T, TT, I, J, A, B. + +LOGIN: MOVE I,LI.IDX(Q) ;get user index of top job of tree + TLZE I,LI%COD ;check that it's really a login. + TLNE I,-1 + BUGCHK Message-type not Login. + IDIV I,LUBLK + CAIL I,NTREES ;make sure logged in trees table is big enough + .LOSE + SKIPN TR.UNM(I) ;make sure table entry not already in use + JRST LOGIN0 + HLRO TT,TR.UNM(I) ;but watch out for wierd screw in ITS. + MOVE T,TR.JNM(I) ;where not logged in job sets its jname + CAMN T,LI.JNM(Q) ;(causing an accounting update) then logs in + AOJE TT,LOGIN0 ;(causing log in of already logged in job). +; ;Following line commented out until bugs in ATTACH/DETACH fixed up. +; BUGCHK That user index already logged in. + +LOGIN0: MOVE T,LI.UNM(Q) ;fill in the table entry + MOVEM T,TR.UNM(I) + MOVE T,LI.JNM(Q) + MOVEM T,TR.JNM(I) + MOVE T,LI.TNM(Q) + MOVEM T,TR.TNM(I) + MOVE TT,LI.TIM(Q) + MOVEM TT,TR.TIM(I) +; MOVE T,LI.XUN(Q) + MOVE T,LI.UNM(Q) ; XUNAME not pushed by sys, screw around + MOVEM T,TR.XUN(I) ; Guess that UNAME is correct + MOVE TT,[-6,,[ SIXBIT /XUNAME/ ? MOVEM T + SIXBIT /UNAME/ ? MOVEM A + SIXBIT /JNAME/ ? MOVEM B ]] + SYSCALL USRVAR,[MOVEI %JSNUM(I) ? MOVE TT] + POPJ P, ; Gone? Give up. + CAMN A,TR.UNM(I) + CAME B,TR.JNM(I) + POPJ P, ; Not the same job? Give up. + TLC T,-1 + TLCE T,-1 + MOVEM T,TR.XUN(I) ; Logged in? Use it! + POPJ P, + +;Procedure to process dmn-push message for log out. +;Q -> the message. Corresponding entry in logged-in tree table +;is found, and cruft is pushed. Later the file will be updated +;from the cruft. +;Uses T, TT, H, I, J, A, B, C. + +LOGOUT: MOVE I,LO.IDX(Q) ;get user index of top job of tree + TLZE I,LO%COD ;check that it's really a logout. + TLNE I,-1 + BUGCHK Message-type not Logout. + IDIV I,LUBLK + CAIL I,NTREES ;make sure logged in trees table is big enough + .LOSE + SETZB A,C ;no connect time nor trmnam if missed log in. + MOVE B,LO.UNM(Q) ;no xuname if missed log in. + MOVEI TT,9 ;no hour if missed log in. + SKIPN TR.UNM(I) + JRST LOGOU0 ;jump if missed log in. + MOVE TT,LO.UNM(Q) ;make some checks + CAME TT,TR.UNM(I) + JRST LOGOU3 + MOVE TT,LO.JNM(Q) + CAME TT,TR.JNM(I) + JRST LOGOU3 + MOVE A,LO.TIM(Q) ;get connect time + SUB A,TR.TIM(I) + JUMPL A,[ BUGCHK Negative connect time. + MOVEI A,0 + JRST .+1 ] + MOVE B,TR.XUN(I) ;get XUNAME + MOVE C,TR.TNM(I) ;get TRMNAM + SETZM TR.UNM(I) ;guy is now logged out + .CALL [ SETZ ;compute hour of login in TT + 'RQDATE + MOVEM T + SETZM T ] ;QDATE system came up + SETO T, + MOVEI TT,9 ;9 AM is default if + AOJE T,LOGOU0 ; sys doesn't know time + MOVEI T,-1(T) + IMULI T,15. ;30ths since midnight when system came up + ADD T,TR.TIM(I) ;30ths since midnight of login + IDIVI T,3600.*30. ;hours since midnight of login + IDIVI T,24. ;modulo 24 in case system up more than one day + +ifn $$STAT,aos crftys ;count this for statistical purposes + +logou0: pushj p,getcor ;allocate one crufty + popj p, ; no core. + MOVEM A,CF.CTM(H) + MOVEM B,CF.UNM(H) + MOVEM C,CF.TNM(H) + MOVEM TT,CF.HOR(H) + MOVE T,LO.JNM(Q) + MOVEM T,CF.JNM(H) + MOVE T,LO.RTM(Q) ;HLRZ if still had old 4.069 usec clock + addi t,4166. ;round, + idivi t,8333. ;converting to seconds*30. + MOVEM T,CF.RTM(H) + MOVE T,LO.SWI(Q) + MOVEM T,CF.SWI(H) +ifn $$mcp,[ + setzm cf.mct(h) ;MACSYMA type is counted elsewhen + setzm cf.mrt(h) +];mcp + PUSHJ P,RDATIM ;TT gets date, T gets time + MOVEM TT,CF.DAT(H) + MOVEM T,CF.TIM(H) + SETOM CF.VAL(H) + POPJ P, + +;This BUGCHK commented out due to ITS lossage....8/9/76 +LOGOU3: ;BUGCHK Logout Tree doesn't match logged-in tree. + SETZM TR.UNM(I) + JRST LOGOU0 + + +getcor: MOVEI H,CF.LEN ;push onto end of cruft table + ADDB H,CRUFTP +getc1a: CAMG H,CRUFTE + jrst getcr1 + +ifn $$STAT,aos coraos ;count how often we + MOVE T,CRUFTE ;need more core + + LSH T,-10. + CAIL T,-3 + .LOSE ;URK + .CALL [ SETZ + 'CORBLK + MOVEI %CBRED+%CBWRT+%CBNDR+%CBNDW + MOVEI %JSELF + MOVEI (T) + SETZI %JSNEW ] + JRST [ MOVEI TT,5*30. ;CAN'T GET CORE, WAIT 5 SEC + .SLEEP TT, + XCT .-1 ;TRY AGAIN + JRST getcrb ;STILL LOSING, BARF + JRST .+1 ] ;WON AFTER ALL + MOVEI T,1_10. + ADDM T,CRUFTE + JRST getc1a + +getcrb: BUGCHK Can't get core to expand cruft table. + MOVEI H,10.*30. ;WAIT 10 SECONDS BEFORE TRYING ANYTHING + .SLEEP H, + MOVNI H,CF.LEN + ADDM H,CRUFTP + POPJ P, + +getcr1: cail h,cruftz+- ;is it getting big? + jrst [setom dmpcnt ; yes, request dump soon + .suset [.sipirqc,,[%pirlt]] ;And speed things up a bit + jrst .+1] + subi h,cf.len ;h -> new cruft. + jrst popj1 ;return + +;Defensive routine to find out the date and time. +;TT gets date, T gets time, nothing clobbered. +;Sets stuff to -1 if it wouldn't have done for the duke. + +RDATIM: .RDATIM T, + PUSH P,A + PUSH P,B + PUSHJ P,RDATI1 + EXCH T,TT + PUSHJ P,RDATI1 + EXCH T,TT + POP P,B + POP P,A + POPJ P, + +;Subroutine to fix T +RDATI1: JUMPLE T,RDATI9 ;ITS knows it's losing + MOVE B,[440600,,T] +RDATI2: ILDB A,B ;Check for garbage characters + CAIL A,'0 + CAILE A,'9 + JRST RDATI9 + TLNE B,770000 + JRST RDATI2 ;Needn't check for wrong year, month 13, etc. + POPJ P, ;since dragon doesn't flame at those anyway. + +RDATI9: SETOB T,TT ;lossage, don't trust any of it + POPJ P, + +SUBTTL Idle Loop + +;This is where we sit when there's nothing to do. +;.HANG on the daemon buffer. +;Also, every 15 minutes do a file-update. +;If system goes down, wait for full down-ness then log out self, sys, and +;core and perform final file-update. + +IDLE: PUSHJ P,DSKLOG ;Log disk errors. + MOVE T,@TIME ;Check for need to run hourly daemon kludge + SUB T,RYGTIM + CAIGE T,3600.*30. + JRST IDLE01 + move a,[sixbit /hourly/] + pushj p,batch +IDLE1B: MOVE T,@TIME + MOVEM T,RYGTIM' +IDLE01: move t,dmpinv ;15 minutes (unless sys going down) + movem t,dmpcnt ; from now do update + .SUSET [.SMASK,,[%PIRLT+%PICLI+%PIDWN+%PIPDL]] +IDLE00: MOVE T,LDMNBD +IDLE0: CAMN T,@DMNBD ; PC will be IDLE0 +IDLE1: .HANG ; or IDLE1 if interrupt out +SHUTD0: PUSHJ P,DMNPOP ;gobble down any daemon messages + SKIPL @DEDTIM ;unless ITS is down, + JRST IDLE00 ;wait more. + MOVE T,@TIME ;save time that system went down. + SKIPN DWNTIM + MOVEM T,DWNTIM + SUB T,DWNTIM ;# 30ths since shutdown + CAIL T,5*30. ;wait at most 5 seconds for other daemons to logout. + JRST SHUTD2 + MOVE R,@USRHI ;see how many jobs are still on the system + SETZ A, +SHUTD1: SUB R,LUBLK + SKIPE @UNAME + AOS A + JUMPG R,SHUTD1 + CAILE A,3 + JRST IDLE00 ;some OPTLIV daemon hasn't logged out yet. +SHUTD2: MOVE R,@USRHI ;Time to go. +SHUTD3: SUB R,LUBLK ;Log out the jobs that are left (sys, core, us). + SKIPE @UNAME + SKIPL @SUPPRO + JRST SHUTD4 + MOVEI Q,FAKMSG ;fake up the dmn-push message + HRRM R,LO.IDX(Q) ;see DMNPLO and LOGUSE in ITS. + MOVE T,@TIME + MOVEM T,LO.TIM(Q) + MOVE T,@UNAME + MOVEM T,LO.UNM(Q) + MOVE T,@JNAME + MOVEM T,LO.JNM(Q) + MOVE TT,@UTRNTM + ADD TT,@TRUNTM + MOVE T,@USIPRQ + ADD T,@TSIPRQ + MOVEM TT,LO.RTM(Q) + MOVEM T,LO.SWI(Q) + PUSHJ P,LOGOUT ;gobble down this fake message +SHUTD4: JUMPG R,SHUTD3 + JRST FILEUP ;Do final FILEUP and .LOGOUT + +SUBTTL Interrupt handler + +TSINT: setz p ;push the .JPC and .SUUOH and miscellany ... + %piioc ? 0 ? -1 ? -1 ? iocint ;IOC errors + %pidwn ? 0 ? 0 ? 0 ? dwnint ;only sets flags, don't defer anything + ;%PIRLT and %PICLK defer each other to prevent + ;contention for pushing cruft + ;%PIRLT's get delayed if they happen while not + ;idle, so there can be no contention from + ;%PIRLT's vs. MP cruft pushes. + %piclk ? 0 ? %piclk\%pirlt\%picli ? 0 ? clkint ;finish up first + %pirlt ? 0 ? %pirlt\%picli\%pidwn\%piclk ? 0 ? rltint ;time-critical + %picli ? 0 ? %pirlt\%picli ? 0 ? cliint ;defer %PIRLT so handler exits + ;before getting %PIRLT it gives itself. +intlen==.-tsint + + +;Here on system-going-down interrupt + +DWNINT: PUSH P,T + SKIPE T,@DEDTIM + JRST DWNIN1 + SETZM DWNTIM ;ITS revived. + movni t,31 ;back to normal intervals + movem t,dmpinv + setom maxinv ;count out once per clock tick. + setom maxcnt + movei t,60.*3600./100. ;interval under normalcy + movem t,rltinv + jrst dismst ;return + +DWNIN1: CAIL T,2*60.*60. ;Going down in less than two minutes? + jrst dismst ;No, don't panic. + movni t,4 ;Yes, start checking world every 2 seconds. + came t,dmpinv ;is it already schedualled sooner? + movem t,dmpcnt ; no, schedual it sooner + movem t,dmpinv ;and make rest of world use this interval + movni t,18. ;every 18 ticks (36 secs) do the MACSYMA update + came t,maxinv ;so they don't happen at our accelerated rate. + movem t,maxcnt + movni t,60.*2. ;2. seconds, + movem t,maxinv ;set the interval + move t,[%rlfls\%rlset,,rltinv] ;spead up the clock + .realt t, + jrst dismst + +;Here on real-time interrupt + +RLTINT: PUSH P,T + hrrz t,-4(p) ;get the PC we interrupted from. Idle? + CAIE T,IDLE0 + CAIN T,IDLE1 + JRST RLTIN0 + MOVE T,[%rlfls\%rlset,,[60.]] ;no, check again in a second + .REALT T, + jrst dismst ;dismis from the interrupt + +RLTIN0: move t,[%rlfls\%rlset,,rltinv] ;and hack it for that interval + .realt t, +ifn $$mcp,[ + aosl maxcnt ;if this is a for-real interrupt + pushj p,maxscn ; update MACSYMA's +];mcp + + pop p,t ;restore T + syscal dismis,[%clbit,,(setz) ;dismis to our hack + p + %climm,,rlthak] ;hack our from directly. + .lose %lssys +rlthak: aosge dmpcnt ;time to update the file? + jrst idle00 ; nope, just go hack them some more + + SKIPE T,@DEDTIM ;system down or going down soon? + CAIL T,2*60.*60. ; i.e. 2 minutes + jrst FILEUP ; no, run file update generator + jrst shutd0 ;yes, do shutdown checks + +;Here on slow-clock interrupt. While we aren't idle, every 1/2 +;second we check for dmn messages this way, to avoid losing any. + +CLKINT: INSIRP PUSH P,A B C D E T TT H I J Q R FORTY UUOH + PUSHJ P,DMNPOP + INSIRP POP P,UUOH FORTY R Q J I H TT T E D C B A + jrst dismis ;return + + +;Here on IOCER interrupt. If device full, wait ten seconds then try +;again. If anything else, we're screwed. + +IOCINT: PUSH P,T + .SUSET [.RBCHN,,T] + MOVSI T,.RIOS(T) + HRRI T,T + .SUSET T + LDB T,[.BP (37000),T] ; Get IOCER code + CAIE T,11 ; DEVICE FULL? + jrst [ move t,-4(p) ; No, dismis and instantly .LOSE + hrlm t,losadr ; RH has 1+.LZ %PIIOC + pop p,t + syscal dismis,[movsi (setz) ? move p + move -3(p) ; Restore PC + move -5(p) ; Restore DF1 + move -4(p) ; Restore DF2 + move losadr] ; Do .LOSE + .lose %lssys] + MOVEI T,10.*30. + .SLEEP T, + hrrz t,-4(p) ;get the PC off the stack + CAIL T,UBUGCH + CAILE T,UBUGCX + jrst dismst ;retry the failing instruction. + MOVEI T,UUORET ;disk full while dumping crash file, give up! + movem t,-4(p) + .CLOSE DMPCH, +dismst: pop p,t ;restore T +dismis: syscal dismis,[%clbit,,(setz) ? p] + .lose %lssys + +losadr: 0,,1+.lz %piioc + +;Here on CLI interrupt. Someone wants to edit the accounting file. +;Latch onto the job in question, do a file update, tell the job +;to proceed, and wait for it to go away. + +CLIINT: .OPEN CLICH,[.UII,,'CLA] + JRST CLIINL + .IOT CLICH,UPDATR + .IOT CLICH,UPDATJ + .CALL [ SETZ + SIXBIT/OPEN/ + [10,,CLICH] + ['USR,,] + UPDATR + SETZ UPDATJ ] + JRST CLIINL + .CALL [ SETZ + 'CORBLK + MOVEI %CBRED+%CBNDR + MOVEI %JSELF + MOVEI CMPAGE_-10. + MOVEI CLICH + SETZI 0 ] + JRST CLIINL + SETOM CLIFLG ;cause it to hang up + setom dmpcnt ;make next real-time int cause file update + .suset [.sipirqc,,[%pirlt]] ;cause immediate real-time interrupt + CAIA +CLIINL: BUGCHK CLI Lossage. + .CLOSE CLICH, + jrst dismis + +SUBTTL File update generator + +FILEUP: +ifn $$mcp,[ + pushj p,maxget ;re-map MACSYMA in case it has changed + pushj p,maxlog ;first, log all the MACSYMA's up to now. +];mcp + MOVE Q,CRUFTP + MOVEM Q,CRUFTF ;all cruft to here will be gobbled, more may come in + SUBI Q,CRUFT ;now sort the cruft table by uname + SKIPN CHKALL ;do anyway if need to check file syntax. + SKIPE CLIFLG ;or if hacking CLI + CAIA + JUMPE Q,IDLE ;well, not much to do here + + .SUSET [.SMASK,,[%PICLK+%PIIOC+%PIDWN+%PICLI+%PIPDL]] +FILEU1: MOVEI A,CRUFT ;Start a sort pass + SETZ R, ;this used to be a shell sort, but now it's a bubble. +FILEU2: MOVE B,A ;next step of pass ;maybe it will work. + ADDI B,CF.LEN + CAML B,CRUFTF + JRST FILEU5 ;pass done + MOVE T,CF.UNM(A) ;compare two crufties + CAMG T,CF.UNM(B) + JRST FILEU4 + HRLI A,-CF.LEN ;out of order, exchange +FILEU3: MOVE T,(A) + EXCH T,(B) + MOVEM T,(A) + AOS B + AOBJN A,FILEU3 + AOJA R,FILEU2 + +FILEU4: ADDI A,CF.LEN + JRST FILEU2 + +FILEU5: JUMPG R,FILEU1 ;if exchanged any, do another pass + MOVEI A,CRUFT ;should now be sorted, but I feel insecure... +FILEU6: MOVEI B,CF.LEN(A) + CAML B,CRUFTF + JRST FILEU7 + MOVE T,CF.UNM(A) + CAMLE T,CF.UNM(B) + .VALUE + ADDI A,CF.LEN + JRST FILEU6 + +;Open input and output files +FILEU7: .SUSET [.SSNAME,,SNAME] + .OPEN INCH,[.BAI,,'DSK ? 'DRAGON ? SIXBIT/HOARD/] + .LOSE 1400 + .OPEN OUCH,[.BAO,,'DSK ? SIXBIT/_DRGN_/ ? SIXBIT/BUFFER/] + .LOSE 1400 + SETZM INBC + SETOM BBC + SETOM OUTBC + SETZM NERRS + SETZM LINENO + IRPS FIG,,STCTIM STRTIM STSWAP STLODT STLOTM + SETZM FIG ;reset subtotals since starting a page + TERMIN + IRPS FIG,,GTCTIM GTRTIM GTSWAP + SETZM FIG ;reset grand totals since starting a page + TERMIN +ifn $$mcp,[ + IRPS FIG,,STMCTM STMRTM GTMCTM GTMRTM + SETZM FIG + TERMIN +];mcp + PUSHJ P,GROVEL +;drops through + ;drops in +;Here on EOF. Finish up and return to the idle loop. + +FILFIN: SKIPGE TOTLF + CLBFIL 17,Totals section does not contain TOTALS line. + SETZM TOTLF + SKIPE STOTLF + CLBFIL 17,Sub-total screw. + SETZM STOTLF + SKIPE RANDF + CLBFIL 17,Randoms section doesn't end, probably no Totals section. + SETZM RANDF + SETZM DRANDF + PUSHJ P,WBUF ;dump out the last buffer + .CALL [ SETZ ;and close the output file + 'RENMWO + MOVEI OUCH + [SIXBIT/DRAGON/] + SETZ [SIXBIT/HOARD/] ] + .LOSE 1000 + SKIPE MNTHLF + JRST MNTHL1 + SKIPE NERRS + JRST FILEU8 ;jump if clobbered file to be saved and mail to be sent + .CALL [ SETZ ;save one version back of input file + 'DELETE + [SIXBIT/DSK/] + [SIXBIT/DRAGON/] + SETZ [SIXBIT/SAVE/] ] + JFCL + .CALL [ SETZ + 'RENMWO + MOVEI INCH + [SIXBIT/DRAGON/] + SETZ [SIXBIT/SAVE/] ] + BUGCHK Can't rename input file. +FILU8X: .CLOSE INCH, ;Here when file update complete. + .CLOSE OUCH, + PUSHJ P,LOTUP ;do the LOGOUT TIMES file. + HRRZS CHKALL ;delete program file-checking request + PUSHJ P,GOIDLE ;clean up cruft table + SKIPE YEARF ;perform periodic special processing + PUSHJ P,YEARLY + SKIPE MONTHF + PUSHJ P,MNTHLY + SKIPE DAYF + PUSHJ P,DAILY + SKIPGE @DEDTIM + .LOGOUT ;ka-zap. (finally) + SETZM EDITF ;any previous edits have now been gobbled down + SKIPL CLIFLG + JRST IDLE ;exit from file update stuff + .SUSET [.SIMASK,,[%PICLK]] ;going to hang up waiting for user to edit file. + MOVE T,CMPAGE+100 ;check user's "password" + CAME T,['GEORGE] + JRST FILU8Z + MOVNS CLIFLG ;initial file-update complete. + SETOM EDITF ;tell the user to go ahead. + SKIPE CMPAGE+100 ;wait for user to edit the file. + .HANG +FILU8Z: SETZM CLIFLG ;clear out interlocks + HRROS CHKALL ;check user's edits. + .CALL [ SETZ ;flush communications page. + 'CORBLK + MOVEI 0 + MOVEI %JSELF + SETZI CMPAGE_-10. ] + JFCL + JRST FILEUP ;gobble down edited file and check for errors, + ;also file away cruft accumulated during editing. + +;Call here to restore environment after doing a file-update. +;Clobber T, TT. + +GOIDLE: .SUSET [.SAMASK,,[%PICLK]] ;no more 1/2 second breaks please + movei t,-25. ;reset back to time to wait for next update + movem t,dmpcnt + MOVE T,CRUFTP ;find amount of cruft pushed while updating + SUB T,CRUFTF + JUMPE T,GOIDL1 + HRLZ TT,CRUFTF ;copy it down to beginning of cruft buffer + HRRI TT,CRUFT + BLT TT,CRUFT-1(T) +GOIDL1: MOVEM T,CRUFTP ;fix pointers + MOVEI T,CRUFT + MOVEM T,CRUFTF + ADDB T,CRUFTP + CAIL T,CRUFTZ-100 ;If there are unused + POPJ P, + MOVE T,CRUFTE ; excess cruft pages, + SUBI T,CRUFTZ ; flush them. + JUMPLE T,CPOPJ + LSH T,-10. ;number of such pages. + MOVNS T + MOVSS T + HRRI T,CRUFTZ_-10. ;aobjn pointer to pages + .CALL [ SETZ + 'CORBLK + MOVEI 0 + MOVEI %JSELF + SETZ T ] + .LOSE 1000 ;should never fail. + MOVEI T,CRUFTZ ;reset pointer to end of core + MOVEM T,CRUFTE + POPJ P, + +;Yearly processing + +YEARLY: SETZM YEARF + .SUSET [.SIMASK,,[%PICLK]] + move a,[sixbit /yearly/] + pushj p,batch + .CALL [ SETZ + SIXBIT/OPEN/ + [.BAO,,OUCH] + [SIXBIT/DSK/] + [SIXBIT/MAIL/] + [SIXBIT/>/] + SETZ MALSNM ] + JRST YEARLX + SETOM OUTBC + MOVEI TT,[ASCIZFROM-JOB:DRAGON +SENT-BY:PFTHMG-DRAGON +RCPT:(MAGIC-DRAGON-KEEPER) +SUBJECT:Happy New Year +TEXT;-1 +Well, I couldn't think of anything else that needed to be in the yearly processing. +] + PUSHJ P,ASZW + PUSHJ P,WBUF +YEARLX: .CLOSE OUCH, + .SUSET [.SAMASK,,[%PICLK]] + POPJ P, + +FILEU8: .CALL [ SETZ + 'RENMWO + MOVEI INCH + [SIXBIT/CLBFIL/] + SETZ [SIXBIT/>/] ] + .LOSE 1000 + .CALL [ SETZ ;Send mail + SIXBIT/OPEN/ + [.BAO,,OUCH] + [SIXBIT/DSK/] + [SIXBIT/MAIL/] + [SIXBIT/>/] + SETZ MALSNM ] + .LOSE 1400 + SETOM OUTBC + SKIPN A,UPDATR + JRST FILU8E + MOVEI TT,[ASCIZTO:CM"] + PUSHJ P,ASZW + SETZB B,C + PUSHJ P,SIXW + WCHI 15 + WCHI 12 +FILU8E: MOVEI TT,[ASCIZFROM-JOB:DRAGON +SENT-BY:PFTHMG-DRAGON +RCPT:(MAGIC-DRAGON-KEEPER) +SUBJECT:Clobberage of accounting file +TEXT;-1 +Bad syntax was detected in the accounting file. The offending lines +have been deleted. The bad file is saved as ] + PUSHJ P,ASZW + PUSHJ P,FLNMW + MOVEI TT,[ASCIZ +The errors encountered were: +] + PUSHJ P,ASZW +FILU8A: CAML C,NERRS + JRST FILU8C + CAIL C,LERRBF + JRST FILU8B + MOVE TT,ERRBFZ(C) + PUSHJ P,ASZW + MOVEI TT,[ASCIZ (Line ] + PUSHJ P,ASZW + MOVE A,ERRBFL(C) + PUSHJ P,NUMW + MOVE A,ERRBFA(C) + MOVE B,ERRBFB(C) + SKIPN ERRBFC(C) + JUMPE A,[ JUMPE B,FILU8D ? JRST .+1 ] + WCHI ", + WCHI 40 + PUSH P,C + MOVE C,ERRBFC(C) + PUSHJ P,SIXW + POP P,C +FILU8D: MOVEI TT,[ASCIZ) +] + PUSHJ P,ASZW + AOJA C,FILU8A + +FILU8B: MOVEI TT,[ASCIZetc ad nauseam] + PUSHJ P,ASZW +FILU8C: PUSHJ P,WBUF + JRST FILU8X + +SUBTTL Daily processing + +;Save the accounting file. +;Check for clobbered LOGOUT TIMES file. +;Maybe this should also sort the randoms? + +DAILY: SETZM DAYF + HRROS CHKALL ;Check whole file once a day. + .SUSET [.SIMASK,,[%PICLK]] + move a,[sixbit /daily/] + pushj p,batch + .OPEN INCH,[.BAI,,'DSK ? 'DRAGON ? SIXBIT/SAVE/ ] + JRST DAILX + .OPEN OUCH,[.BAO,,'DSK ? 'DRAGON ? 'YESTER ] + JRST DAILX +DAILY1: MOVE T,[-OUTBFL,,OUTBUF] + .IOT INCH,T + HRLOI TT,-OUTBUF-1(T) + EQVI TT,OUTBUF + .IOT OUCH,TT + JUMPGE T,DAILY1 +DAILX: .CLOSE INCH, + .CLOSE OUCH, + SETOM LOTCHF' + .CALL [ SETZ + SIXBIT/OPEN/ + [.BAI,,INCH] + [SIXBIT/DSK/] + [SIXBIT/LOGOUT/] + [SIXBIT/TIMES/] + SETZ LOTSNM ] + JRST DAILX1 +LOTCH1: MOVE T,[-5,,LOTOLD] + .IOT INCH,T + JUMPGE T,LOTCH2 + CAMN T,[-5,,LOTOLD] + JRST DAILX1 + PUSHJ P,LOTCH9 + MOVEI TT,[ASCIZ\File length not a multiple of 5 words. +\] + PUSHJ P,ASZW + JRST DAILX1 + +LOTCH9: AOSE LOTCHF + POPJ P, + .CALL [ SETZ + SIXBIT/OPEN/ + [.BAO,,OUCH] + [SIXBIT/DSK/] + [SIXBIT/MAIL/] + [SIXBIT/>/] + SETZ MALSNM] + .LOSE 1400 + SETOM OUTBC + MOVEI TT,[ASCIZ\FROM-JOB:DRAGON +SENT-BY:PFTHMG-DRAGON +RCPT:(MAGIC-DRAGON-KEEPER) +TEXT;-1 +The file \] + PUSHJ P,ASZW + PUSHJ P,FLNMW + MOVEI TT,[ASCIZ\ seems to be clobbered. Please check it. +The offensive material follows: +\] + PUSHJ P,ASZW + POPJ P, + +LOTCH2: MOVE B,[440700,,LOTOLD] + MOVE C,[440700,,[ASCIZ\ZZZZZZ99/99/99 99:99:99 +\]] +LOTCH3: ILDB T,B + ILDB TT,C + JUMPE TT,LOTCH1 + CAIN TT,"Z + JRST [ CAIL T,40 + CAIL T,140 + JRST LOTCH4 + JRST LOTCH3 ] + CAIN TT,"9 + JRST [ CAIL T,"0 + CAILE T,"9 + JRST LOTCH4 + JRST LOTCH3 ] + CAMN T,TT + JRST LOTCH3 +LOTCH4: PUSHJ P,LOTCH9 + MOVEI TT,LOTOLD + PUSHJ P,ASZW + MOVEI TT,[ASCIZ/ +/] + PUSHJ P,ASZW + JRST LOTCH1 + +DAILX1: SKIPL LOTCHF + PUSHJ P,WBUF + .CLOSE INCH, + .CLOSE OUCH, + .SUSET [.SAMASK,,[%PICLK]] + POPJ P, + +SUBTTL Monthly processing + +;Save the accounting file as DRAGON lastmonth, +;and reset all the usages to zero. + +MNTHLY: SETZM MONTHF + .SUSET [.SIMASK,,[%PICLK]] + move a,[sixbit /mnthly/] + pushj p,batch + SETOM MNTHLF ;Use regular grovel routines, almost... + HRROS CHKALL ; [this is needed to get all lines processed] + JRST FILEU7 ; upon completion, they will return to MNTHL1 + +;Trap here from GROVL9 for each line in the file. +MNTHL2: SKIPE DRANDF ;if random user with no usage last month, + SKIPE CTIME + JRST MNTHL3 + SKIPN RTIME + SKIPE SWAPS + JRST MNTHL3 + JRST GROVEL ;flush him completely + +MNTHL3: SETZM CTIME ;reset usage + SETZM RTIME + SETZM SWAPS +ifn $$mcp,[ + setzm mctime + setzm mrtime +];mcp + PUSHJ P,WBACK ;write it back out + SKIPN TOTLF ;unless this was final totals line + JRST GROVEL ;and go process more + +ifn $$STAT,[ +ifn $$MCP,[ + MOVEI TT,[ASCIZ\ + + STATS fups crfts crftm core runt nomax normax newfls newcnt oldfls oldcnt + +STATS 0 0 0 0 0.0 0.0 0.0 0 0 0 0 + + FUPS - # of file updates + CRFTYS - # of pieces of cruft pushed from logouts + CRFTYM - # of pieces of cruft pushed from MACSYMAs + CORE - # of times core has been grown. Core is flushed when file updated. + RUNT - runtime consumed by PFTHMG + NOMAX - amount of time during which there were no MACSYMA's on the machine + NORMAX - amount of time during which no one accrued MACSYMA connect time + NEWFLS - # of times new entries in MACSYMA table had to be invalidated + NEWCNT - # of entries so invalidated + OLDFLS - # of times all entries in MACSYMA table had to be invalidated + OLDCNT - # of entries so invalidated + + This file is for period beginning \] +]; END IFN $$MPC, +IFE $$MCP,[ + movei tt,[asciz / + + STATS fups crfts core runt + +STATS 0 0 0 0.0 + + FUPS - # of file updates + CRFTYS - # of pieces of cruft pushed from logouts + CORE - # of times core has been grown. Core is flushed when file updated. + RUNT - runtime consumed by PFTHMG + + This file is for period beginning /] +]; END IFE $$MCP, +]; END IFN $$STAT, + +ife $$stat,[ + movei tt,[asciz / + + This file is for period beginning /] +]; END IFE $$STAT + + PUSHJ P,ASZW + MOVE A,LODAT + PUSHJ P,DATW + WCHI 40 + .rtime a, ;gotta get the time from system + movem a,lotim ;and use it; we don't remember logout times + PUSHJ P,TIMW + MOVEI TT,[ASCIZ\ + + System Uptime Report + +OK \] + MOVE D,LODAT + MOVEM D,OKDAT + MOVE D,LOTIM + MOVEM D,OKTIM + SETZM OKTMUP + MOVEI D,OKDAT + PUSHJ P,UPTRWW + SETZM TOTLF ;avoid screw at FILFIN + POPJ P, ;end file, return out of grovel + +MNTHL1: SKIPE NERRS + .VALUE ;we really fucked-up somehow + LDB T,[141400,,LASDAT] ;rename the file to be last month's report + ANDI T,717 + TRZE T,100 + ADDI T,10. + CAIL T,1 + CAILE T,12. + .VALUE ;random month + .CALL [ SETZ + 'RENMWO + MOVEI INCH + MONTHS(T) + SETZ ['REPORT] ] + .LOSE 1000 + .CALL [ SETZ + SIXBIT/OPEN/ + [.BAO,,OUCH] + [SIXBIT/DSK/] + [SIXBIT/MAIL/] + [SIXBIT/>/] + SETZ MALSNM ] + JRST MNTHL7 + SETOM OUTBC + MOVEI TT,[ASCIZFROM-JOB:DRAGON +SENT-BY:PFTHMG-DRAGON +RCPT:(MAGIC-DRAGON-KEEPER) +SUBJECT:That Time Again +TEXT;-1 +Don't forget to print out the ] + PUSHJ P,ASZW + PUSHJ P,FLNMW + MOVEI TT,[ASCIZ file and +give it to the appropriate people. + - puff +] + PUSHJ P,ASZW + PUSHJ P,WBUF +MNTHL7: .CLOSE OUCH, + .CLOSE INCH, + SETZM MNTHLF + HRRZS CHKALL + .SUSET [.SAMASK,,[%PICLK]] + POPJ P, ;end of monthly processing + +MONTHS: 'FOOBAR + SIXBIT/JAN/ + SIXBIT/FEB/ + SIXBIT/MARCH/ + SIXBIT/APRIL/ + SIXBIT/MAY/ + SIXBIT/JUNE/ + SIXBIT/JULY/ + SIXBIT/AUGUST/ + SIXBIT/SEP/ + SIXBIT/OCT/ + SIXBIT/NOV/ + SIXBIT/DEC/ + +SUBTTL Hack the LOGOUT TIMES file + +;For compatibility with old & name dragons. + +LOTUP: MOVEI Q,CRUFT + CAML Q,CRUFTF + POPJ P, +LOTUP0: SKIPL CF.UNM(Q) ;old dragon used different sort, fix up + JRST LOTUP1 ;make Q point to lowest positive + ADDI Q,CF.LEN + CAMGE Q,CRUFTF + JRST LOTUP0 + MOVE Q,CRUFTF +LOTUP1: MOVE R,Q ;save pntr to lowest positive + MOVE J,CRUFTF ;remember haven't done negatives yet + .CALL [ SETZ + SIXBIT/OPEN/ + [.BAI,,INCH] + [SIXBIT/DSK/] + [SIXBIT/LOGOUT/] + [SIXBIT/TIMES/] + SETZ LOTSNM ] + POPJ P, ;tough rocks + .CALL [ SETZ + SIXBIT/OPEN/ + [.BAO,,OUCH] + [SIXBIT/DSK/] + [SIXBIT/_DRGN_/] + [SIXBIT/TIMES/] + SETZ LOTSNM ] + .LOSE 1400 + PUSHJ P,LOTFILL ;fill LOTNEW +LOTUP5: MOVE T,[-5,,LOTOLD] ;get entry from file + .IOT INCH,T + JUMPL T,LOTEOF +LOTUP4: MOVE A,LOTOLD ;quick compare + LSH A,-1 + SUB A,LOTCMP + JUMPG A,LOTUP6 ;LOTNEW goes first + JUMPL A,LOTUP7 ;LOTOLD goes first + LDB A,[350700,,LOTOLD+1];hmm, check 6th char + LDB B,[350700,,LOTNEW+1] + CAMLE B,A + JRST LOTUP7 ;LOTOLD goes first + CAMN B,A + JRST LOTUP8 ;LOTNEW replaces LOTOLD +LOTUP6: MOVE T,[-5,,LOTNEW] ;Put LOTNEW first + .IOT OUCH,T + MOVE D,LOTCMP +LOTUP3: MOVE E,LOTNEW+1 + PUSHJ P,LOTFILL ;get new LOTNEW + CAME D,LOTCMP + JRST LOTUP4 + XOR E,LOTNEW+1 + TLNN E,774000 + JRST LOTUP3 ;this one the same, get another + JRST LOTUP4 + +LOTUP7: MOVE T,[-5,,LOTOLD] ;put LOTOLD first + .IOT OUCH,T + JRST LOTUP5 ;and get a new one + +LOTUP8: MOVE T,[LOTNEW,,LOTOLD] ;LOTNEW replaces LOTOLD + BLT T,LOTOLD+4 + PUSHJ P,LOTFILL ;get new LOTNEW + JRST LOTUP4 + +LOTEOF: MOVSI A,377777 ;EOF on old file + CAME A,LOTCMP ;See if EOF on new also + JRST LOTUP8 ;No, read through rest of new + .CLOSE INCH, + .CALL [ SETZ ;Install new version + 'RENMWO + MOVEI OUCH + ['LOGOUT] + SETZ [SIXBIT/TIMES/]] + .LOSE 1000 + .CLOSE OUCH, + POPJ P, + +LOTFILL:CAML Q,J + JRST LOTFL1 ;This section of cruft table exhausted + MOVE A,CF.JNM(Q) + CAME A,['HACTRN] ;Only do legitimate human users + JRST LOTFL4 + HLRO A,CF.UNM(Q) + AOJE A,LOTFL4 ;Bastard + MOVE B,[440600,,CF.UNM(Q)] + MOVE C,[440700,,LOTNEW] +LOTFL0: ILDB A,B + ADDI A,40' + IDPB A,C + TLNE B,770000 + JRST LOTFL0 + MOVE A,CF.DAT(Q) ;MMDDYY + ROT A,14 + MOVEM A,CF.DAT(Q) + MOVE B,[440600,,CF.DAT(Q)] + MOVEI TT,6+6 +LOTFL3: ILDB A,B + ADDI A,40' + IDPB A,C + TRNE TT,1 + IBP C + SOJG TT,LOTFL3 + MOVE A,LOTNEW ;set up quick compare word + LSH A,-1 + MOVEM A,LOTCMP' + ADDI Q,CF.LEN + POPJ P, + +LOTFL1: JUMPE R,LOTFL2 + MOVEI Q,CRUFT ;do negatives + MOVE J,R + MOVEI R,0 + JRST LOTFILL + +LOTFL2: MOVSI A,377777 ;make dummy entry + MOVEM A,LOTCMP + POPJ P, + +LOTFL4: ADDI Q,CF.LEN ;next + JRST LOTFILL + +SUBTTL Grovel over accounting file + +;Grovel over the accounting file, updating according to the cruft table. + +GROVEL: AOS LINENO ;starting a new line of input + SETZM UNAMEA ;haven't seen a uname yet + SETZM UNAMEB ;.. + SETZM UNAMEC ;.. +GROVL0: PUSHJ P,RCH ;get first character in line + CAILE T,40 ;skip if white space or eof + JRST GROVL1 + CAIE T,^L ;formfeed is considered to end the randoms section... + JRST GVLCPY + IRPS FIG,,STCTIM STRTIM STSWAP STLODT STLOTM + SETZM FIG ;reset subtotals since ending a page + TERMIN +ifn $$mcp,[ + SETZM STMCTM + SETZM STMRTM +];mcp + SKIPE RANDF ;if ending randoms section, add new randoms here + PUSHJ P,SPECR1 + SETZM DRANDF + WCHI ^L + JRST GROVL0 + +GVLCPY: JUMPL T,CPOPJ ;return from GROVEL if EOF. + PUSHJ P,WCH ;copy the line over verbatim + CAIN T,12 + JRST GROVEL +GVLCP1: PUSHJ P,RCH + JRST GVLCPY + +GVLFL1: PUSHJ P,RCH +GVLFLS: JUMPL T,CPOPJ ;similar to GVLCPY but flush rest of line + CAIN T,12 + JRST GROVEL + jrst gvlfl1 + +GROVL1: CAIN T,"- ;lines of dashes introduce special sections + JRST SPEC0 + pushj p,untyi ;buffer back the first char of line + SETZM LVRBEG ;default unspecified stuff to 0 + MOVE T,[LVRBEG,,LVRBEG+1] + BLT T,LVREND-1 + PUSHJ P,SIXR ;get the uname spec of this line + pushj p,untyi ;buffer back delimiter + MOVEM A,UNAMEA + MOVEM B,UNAMEB + MOVEM C,UNAMEC + SKIPE TOTLF + JRST GRVL1T + SKIPE STOTLF + JRST GRVL1S + MOVE E,P + SKIPN CHKALL + PUSHJ P,UCRUFT ;see if this line's getting hacked + JRST GROVL2 +GRVLNH: MOVE A,UNAMEA ;nope, just put out the uname + MOVE B,UNAMEB + MOVE C,UNAMEC + PUSHJ P,SIXW + JRST GVLCP1 ;and copy the rest verbatim + +GROVL2: MOVE P,E ;this line's getting hacked, gobble it down +GROVL3: PUSHJ P,SIGCH + CAIG T,40 + JRST GROVL9 ;end of line + CAIE T,"j + CAIN T,"J + JRST GROVL4 + CAIE T,"a + CAIN T,"A + JRST GROVL5 + CAIE T,"h + CAIN T,"H + JRST GROVL6 +;drops through + ;drops in + pushj p,untyi + move tt,column ;column before delimiter + movem tt,ctimep + pushj p,numf + clbfil 0,Garbage character where connect-time expected. +ifn $$MCP,pushj p,hread ;get connect time from hours.xx +ife $$MCP,pushj p,dhmsr ;get connect time from D!HH:MM:SS + movem a,ctime + pushj p,sigch + caig t,40 + jrst grovl9 ;end of line + pushj p,untyi + move tt,column + movem tt,rtimep + pushj p,numf + clbfil 0,Garbage character where run-time expected. +ifn $$MCP,pushj p,hread ;get run time from HOURS.xxx +ife $$MCP,pushj p,dhmsr ;get run time from D!HH:MM:SS + movem a,rtime + pushj p,sigch + caig t,40 + jrst grovl9 ;end of line + pushj p,untyi + move tt,column + movem tt,swapsp + pushj p,numf + clbfil 0,Garbage character where swap-in count expected. + pushj p,numr ;get number of swaps + movem a,swaps + pushj p,sigch + caig t,40 + jrst grovl9 ;end of line +ifn $$MCP,[ + pushj p,untyi + move tt,column + movem tt,mctimp ;remember where we found this + pushj p,numf ;check for bad char + clbfil 0,Garbage character where MACSYMA connect time expected. + pushj p,hread ;read the time + movem a,mctime ;and remember it + pushj p,sigch ;get next significant char + caig t,40 ;end of line? + jrst grovl9 ; yes + pushj p,untyi ;buffer it back + move tt,column + movem tt,mrtimp ;remember where we found this + pushj p,numf ;check it for bad + clbfil 0,Garbage character where MACSYMA run time expected. + pushj p,hread ;read the run time + movem a,mrtime ;remember it + pushj p,sigch ;and get the next significant char + caig t,40 ;end of line? + jrst grovl9 ; yes +] ; END IFN $$MCP, + pushj p,untyi ;buffer it back + move tt,column + movem tt,lodatp + pushj p,numf + clbfil 0,Garbage character where logout date expected. + pushj p,datr ;get logout date + movem a,lodat + pushj p,sigch + caig t,40 + jrst grovl9 ;end of line + pushj p,untyi + move tt,column + movem tt,lotimp + pushj p,numf + clbfil 0,Garbage character where logout time expected. + pushj p,timr ;get logout time + movem a,lotim +grvl9a: pushj p,sigch ;get char that ends line +grovl9: caie t,15 + clbfil 0,Garbage character. + pushj p,rch + caie t,12 + pushj p,untyi + pushj p,coldef ;default columns of unspecified data. + SKIPE MNTHLF + JRST MNTHL2 ;if monthly processing, zero usage before writing back + SKIPE TOTLF + JRST SPECT2 ;This is totals line, go add in all crufts. + SKIPE STOTLF + JRST SPECS2 ;Process subtotals + MOVE A,UNAMEA + MOVE B,UNAMEB + MOVE C,UNAMEC + PUSHJ P,UCRUFT + UPDUSR ;update this line from cruft + PUSHJ P,WBACK ;write it back out + JRST GROVEL ;go do next line + +;Skip if char in T is a numeric digit. + +NUMF: CAIL T,"0 + CAILE T,"9 + POPJ P, + JRST POPJ1 + +GROVL4: pushj p,untyi + PUSHJ P,SIXR + CAMN A,[SIXBIT/JOB/] + CAIE T,"= + CLBFIL 0,Bad JOB= Spec. + PUSHJ P,SIXR + pushj p,untyi + MOVEM A,JNAMEA + MOVEM B,JNAMEB + MOVEM C,JNAMEC + SETOM JNAMEF + JUMPN A,GROVL3 + JUMPN B,GROVL3 + JUMPN C,GROVL3 + CLBFIL 0,Null JOB= Spec. + +GROVL5: pushj p,untyi + PUSHJ P,SIXR + CAMN A,[SIXBIT/ACCT/] + CAIE T,"= + CLBFIL 0,Bad ACCT= Spec. + PUSHJ P,SIXR + pushj p,untyi + MOVEM A,ACCNTA + MOVEM B,ACCNTB + MOVEM C,ACCNTC + SETOM ACCNTF + JUMPN A,GROVL3 + JUMPN B,GROVL3 + JUMPN C,GROVL3 + CLBFIL 0,Null ACCT= Spec. + +GROVL6: pushj p,untyi + PUSHJ P,SIXR + CAMN A,[SIXBIT/HOURS/] + CAIE T,"= + CLBFIL 0,Bad HOURS= Spec. + PUSHJ P,NUMR + MOVEM A,FHOUR + PUSHJ P,RCH + CAIE T,"- + CLBFIL 0,HOURS= Spec not followed by two numbers. + PUSHJ P,NUMR + MOVEM A,LHOUR + SETOM HOURSF + JRST GROVL3 + +;Default columns of unspecified items. +;Clobber T. + +IFN $$MCP,[ +COLDEF: MOVEI T,21. ;default starting places for unspecified fields + IRPS FIG,,[CTIMEP RTIMEP SWAPSP mctimp mrtimp LODATP + ]WID,,[10. 11. 7. 10. 11. 10. ] + SKIPE FIXIND + SETZM FIG + SKIPE FIG + SKIPA T,FIG + MOVEM T,FIG + ADDI T,WID + TERMIN + POPJ P, +] ; END IFN $$MCP, +IFE $$MCP,[ +COLDEF: MOVEI T,21. ;default starting places for unspecified fields + IRPS FIG,,[CTIMEP RTIMEP SWAPSP LODATP LOTIMP + ]WID,,[13. 10. 7. 10. 10. ] + SKIPE FIXIND + SETZM FIG + SKIPE FIG + SKIPA T,FIG + MOVEM T,FIG + ADDI T,WID + TERMIN + POPJ P, +] ; END IFE $$MCP, + + +SUBTTL Write back a line + +wback: setzm column + MOVE A,UNAMEA + jumpe a,cpopj ;don't write wild-care UNAMEs + MOVE B,UNAMEB + MOVE C,UNAMEC + PUSHJ P,SIXW + SKIPN JNAMEF + JRST WBACK1 + MOVEI TT,[ASCIZ/ JOB=/] + PUSHJ P,ASZW + MOVE A,JNAMEA + MOVE B,JNAMEB + MOVE C,JNAMEC + PUSHJ P,SIXW +WBACK1: SKIPN ACCNTF + JRST WBACK2 + MOVEI TT,[ASCIZ/ ACCT=/] + PUSHJ P,ASZW + MOVE A,ACCNTA + MOVE B,ACCNTB + MOVE C,ACCNTC + PUSHJ P,SIXW +WBACK2: SKIPN HOURSF + JRST WBACK3 + MOVEI TT,[ASCIZ/ HOURS=/] + PUSHJ P,ASZW + MOVE A,FHOUR + PUSHJ P,NUMW + WCHI "- + MOVE A,LHOUR + PUSHJ P,NUMW +WBACK3: SKIPN CTIME ;if all 0, don't write any figures + SKIPE RTIME + JRST WBACK4 + SKIPN LODAT + SKIPE LOTIM + JRST WBACK4 +ifn $$mcp,[ + skipn mctime + skipe mrtime + jrst wback4 +];mcp + SKIPN SWAPS + JRST CRLF +wback4: move t,ctimep + PUSHJ P,COLADJ + MOVE A,CTIME + SKIPE CHKALL + ADDM A,STCTIM +ifn $$MCP,pushj p,hwrit2 ;connect time in hours.xx +ife $$MCP,pushj p,dhmsw ;connect time in D!HH:MM:SS + move t,rtimep + PUSHJ P,COLADJ + MOVE A,RTIME + SKIPE CHKALL + ADDM A,STRTIM +ifn $$MCP,pushj p,hwrit3 ;run time in hours.xx +ife $$MCP,pushj p,dhmsw ;run time in D!HH:MM:SS + move t,swapsp + PUSHJ P,COLADJ + MOVE A,SWAPS + SKIPE CHKALL + ADDM A,STSWAP + PUSHJ P,NUMW + +ifn $$MCP,[ + move t,mctimp ;get column to start MACSYMA connect time in + pushj p,coladj ;and adjust our position + move a,mctime ;get the user's MACSYMA connect time + skipe chkall ;if we're counting them + addm a,stmctm ; add it into the subtotal + pushj p,hwrit2 ;write it with 2 post-decimal digits + move t,mrtimp ;get column to start MACSYMA run time in + pushj p,coladj ;and adjust our posititon + move a,mrtime ;get the user's MACSYMA run time + skipe chkall ;if we're taking subtotals + addm a,stmrtm ; count this in the subtotal + pushj p,hwrit3 ;write it with 3 post-decimal digits +] ; END IFN $$MCP, + + move t,lodatp + PUSHJ P,COLADJ + SKIPE A,LODAT + CAMN A,[-1] + JRST WBACK5 + SKIPE CHKALL + MOVEM A,STLODT + PUSHJ P,DATW +WBACK5: +ife $$MCP,[ + move t,lotimp + PUSHJ P,COLADJ + SKIPE A,LOTIM + CAMN A,[-1] + JRST CRLF + SKIPE CHKALL + MOVEM A,STLOTM + PUSHJ P,TIMW +] ;END IFE $$MCP, + +CRLF: WCHI 15 + WCHI 12 + POPJ P, + +SUBTTL Special sections + +;Here from GROVEL when row of dashes encountered. Begin special section. + +SPEC0: PUSHJ P,RCH ;find non-dash + CAIE T,40 + CAIN T,"- + JRST SPEC0 + MOVE Q,T ;save section type letter + CAIL Q,"a + SUBI Q,40 + SKIPE TOTLF + CLBFIL 0,Totals section does not contain TOTALS line. + SKIPE STOTLF + CLBFIL 0,Subtotal screw. + SKIPE RANDF ;if ending randoms section, add new randoms + PUSHJ P,SPECR1 + SETZM DRANDF +SPEC1: PUSHJ P,RCH ;gobble down rest of line + CAIE T,12 + JUMPGE T,SPEC1 + MOVSI I,-LSPECT ;look up section type in table + LDB T,[350700,,@SPECNM(I)] + CAME T,Q + AOBJN I,.-2 + SKIPL I + CLBFIL 0,Row of dashes of unrecognized type. + MOVE TT,SPECNM(I) ;compute length of special name + HRLI TT,440700 + MOVNI A,1 ;A will get (- (+ 2 length)) +SPEC1A: ILDB T,TT + SOS A + JUMPN T,SPEC1A + ADDI A,68. ;number of dashes to fill in with + LSH A,-1 + MOVE T,A ;copy dashes into output file + WCHI "- + SOJG T,.-1 + WCHI 40 + MOVE TT,SPECNM(I) + PUSHJ P,ASZW + WCHI 40 + MOVE T,A + WCHI "- + SOJG T,.-1 + WCHI 15 + WCHI 12 + SKIPN MNTHLF + JRST @SPECAD(I) ;dispatch to appropriate handler + JRST @SPECMO(I) + +SPECNM: [ASCIZ/RANDOMS/] ;names of special sections + [ASCIZ/TOTALS/] + [ASCIZ/PAGE SUBTOTALS/] +LSPECT==.-SPECNM + +SPECAD: SPECRN ;normal dispatch for special section + SPECTT + SPECST +IFN .-SPECAD-LSPECT, .ERR SPECAD DISAGREES WITH SPECNM + +SPECMO: SPECMR ;dispatch for during monthly processing + SPECTT + GROVEL +IFN .-SPECMO-LSPECT, .ERR SPECMO DISAGREES WITH SPECNM + +SPECMR: SETOM DRANDF ;delete useless randoms + JRST GROVEL + +;Random users begin here. What we do is put any otherwise +;unaccounted for users at the END of this section. + +SPECRN: SETOM RANDF + JRST GROVEL + +;Call here when end of randoms section is reached. Preserves only Q. + +SPECR1: PUSH P,Q + SETZM RANDF + JRST SPECR9 + +SPECR2: SKIPN CF.VAL(Q) + JRST SPECR7 + SETZM LVRBEG ;Found a user not yet accounted for. + MOVE T,[LVRBEG,,LVRBEG+1] + BLT T,LVREND-1 ;So fake up an accounting entry for that user. + MOVE T,CF.UNM(Q) + MOVEM T,UNAMEA + MOVE T,CF.JNM(Q) + MOVEM T,JNAMEA + PUSHJ P,NRJNMP + SETOM JNAMEF ;unusual jname, record it + PUSHJ P,COLDEF ;using default columns +SPECR3: PUSHJ P,UPDUS3 ;update fake accounting from the data +SPECR4: ADDI Q,CF.LEN ;look for more cruft for the same user + CAML Q,CRUFTF + JRST SPECR8 + MOVE T,CF.UNM(Q) + SKIPE CF.VAL(Q) + CAME T,UNAMEA + JRST SPECR4 + MOVE T,CF.JNM(Q) + SKIPN JNAMEF + JRST [ PUSHJ P,NRJNMP + JRST SPECR4 + JRST SPECR3 ] + CAME T,JNAMEA + JRST SPECR4 + JRST SPECR3 ;found some, gobble it down too + +SPECR8: PUSHJ P,WBACK ;write it out +SPECR9: MOVEI Q,CRUFT-CF.LEN ;Look for more randoms. +SPECR7: ADDI Q,CF.LEN + CAMGE Q,CRUFTF + JRST SPECR2 + POP P,Q + POPJ P, + +;Skip if T is a prosaic jname. Clobber T. +NRJNMP: CAMN T,['HACTRN] + JRST POPJ1 + AND T,[777777,,767070] + CAMN T,['JOB.00] + JRST POPJ1 + POPJ P, + +;Here for page subtotals. Next line is like a totals line +;but only stuff on this page is updated into it. + +SPECST: SETOM STOTLF ;tell groveler to process a little differently + JRST GROVEL + +GRVL1S: CAME A,['TOTALS] + CLBFIL 0,TOTALS line missing after PAGE SUBTOTALS header. + JRST GROVL3 + +SPECS2: +ifn $$mcp,[ + IRPS FIG1,OP,[CTIME+RTIME+SWAPS+MCTIME+MRTIME+LODAT LOTIM]FIG2,,[STCTIM STRTIM STSWAP STMCTM STMRTM STLODT STLOTM] + MOVE T,FIG2 ;increase page subtotals + SKIPE CHKALL + SETZM FIG1 ;recalculating + IFSE OP,+, ADDM T,FIG1 + .ELSE [ SKIPE T + MOVEM T,FIG1 ] + TERMIN +];$$mcp +ife $$mcp,[ + IRPS FIG1,OP,[CTIME+RTIME+SWAPS+LODAT LOTIM]FIG2,,[STCTIM STRTIM STSWAP STLODT STLOTM] + MOVE T,FIG2 ;increase page subtotals + SKIPE CHKALL + SETZM FIG1 ;recalculating + IFSE OP,+, ADDM T,FIG1 + .ELSE [ SKIPE T + MOVEM T,FIG1 ] + TERMIN +];$$mcp + PUSHJ P,WBACK ;write it back out +ifn $$mcp,[ + IRPS FIG1,,[GTCTIM GTRTIM GTSWAP GTMCTM GTMRTM]FIG2,,[CTIME RTIME SWAPS MCTIME MRTIME] + MOVE T,FIG2 ;update grand totals + ADDM T,FIG1 + TERMIN +];mcp +ife $$mcp,[ + IRPS FIG1,,[GTCTIM GTRTIM GTSWAP]FIG2,,[CTIME RTIME SWAPS] + MOVE T,FIG2 ;update grand totals + ADDM T,FIG1 + TERMIN +];mcp + SETZM STOTLF ;end subtotal processing + JRST GROVEL ;continue normal grovelling + +;Come here to generate totals section. +;First comes a line for user "TOTALS" which totals all the usage. +;then comes the STATS line which gets statistics on PUFF's operation, +;then the system uptime report + +SPECTT: SETOM TOTLF ;flag for totals mode. + JRST GROVEL + +GRVL1T: SKIPL TOTLF + JRST GRVL2T + CAME A,['TOTALS] + CLBFIL 0,Totals section does not begin with TOTALS line. + JRST GROVL3 + +SPECT2: MOVEI Q,CRUFT ;Returns here after gobbling existing totals. + MOVE T,LODAT ;Save date file last updated. + MOVEM T,LASDAT +SPECT3: CAML Q,CRUFTF + JRST SPECT4 + PUSHJ P,UPDUS3 ;Add in this piece of cruft + ADDI Q,CF.LEN + JRST SPECT3 + +SPECT4: SKIPN CHKALL ;If recalculating total + JRST SPCT4A + MOVE T,GTCTIM + MOVEM T,CTIME + MOVE T,GTRTIM + MOVEM T,RTIME + MOVE T,GTSWAP + MOVEM T,SWAPS +ifn $$mcp,[ + move t,gtmctm + movem t,mctime + move t,gtmrtm + movem t,mrtime +];$$mcp +SPCT4A: PUSHJ P,RDATIM ;T gets time, TT gets date + SKIPLE T + MOVEM T,LOTIM ;set date/time file last updated. + JUMPLE TT,SPECT5 + MOVEM TT,LODAT + SKIPG T,LASDAT ;compare this date against previous + JRST SPECT5 ;if known + XOR T,TT ;see what differs + TLNE T,777700 + SETOM YEARF + TDNE T,[77770000] + SETOM MONTHF + TRNE T,7777 + SETOM DAYF +SPECT5: PUSHJ P,WBACK ;write it out + MOVNS TOTLF ;set TOTLF to 1 to process uptime cruft + JRST GROVEL + +;Here for a line of uptime report. Should be UP, DOWN, or OK + +GRVL2T: CAME A,[SIXBIT/UP/] ;UP and DOWN we just copy over + CAMN A,[SIXBIT/DOWN/] + JRST GRVLNH +ifn $$STAT,[ + camn a,[sixbit /STATS/] ;PUFF's internal stats + jrst grvlst ; go handle them +]; END $$STAT, + + CAME A,[SIXBIT/OK/] + CLBFIL 0,Word other than UP, DOWN, or OK in uptime report. + PUSHJ P,SIGCH + pushj p,untyi + PUSHJ P,DATR + MOVEM A,NOKDAT + PUSHJ P,SIGCH + pushj p,untyi + PUSHJ P,TIMR + MOVEM A,NOKTIM + PUSHJ P,SIGCH + pushj p,untyi +ifn $$MCP,pushj p,hread ;get run time from HOURS.xxx +ife $$MCP,pushj p,dhmsr ;get run time from D!HH:MM:SS + MOVEM A,NOKTMU + PUSHJ P,RDATIM ;TT gets date, T gets time + EXCH TT,OKDAT + EXCH T,OKTIM + CAMN T,NOKTIM + CAME TT,NOKDAT + JRST WASDWN +STILUP: .RDTIME T, + MOVEM T,OKTMUP + MOVEI TT,[ASCIZ/OK /] + MOVEI D,OKDAT + PUSHJ P,UPTRWW + JRST GVLFL1 + + +WASDWN: MOVEI TT,[ASCIZ/DOWN /] + MOVEI D,NOKDAT + PUSHJ P,UPTRWW + MOVE D,NOKDAT + PUSHJ P,6DTCNV + MOVE B,A + MOVE D,OKDAT + PUSHJ P,6DTCNV + SUBM A,B ;B:=NUMBER OF DAYS DOWN + MOVE D,NOKTIM + PUSHJ P,6TMCNV + MOVE C,A + MOVE D,OKTIM + PUSHJ P,6TMCNV + SUB A,C ;A:=NUMBER OF SECONDS*30. + + IMULI B,24.*60.*60.*30. + + ADD A,B + MOVEM A,OKTMUP ;STORE LENGTH OF TIME DOWN + MOVEI TT,[ASCIZ/UP /] + MOVEI D,OKDAT + PUSHJ P,UPTRWW + JRST STILUP + +UPTRWW: SETZM COLUMN + PUSHJ P,ASZW ;WRITE LINE TO UPTIME REPORT + MOVE A,OKDAT-OKDAT(D) + PUSHJ P,DATW + WCHI 40 + MOVE A,OKTIM-OKDAT(D) + PUSHJ P,TIMW + WCHI 40 + MOVE A,OKTMUP-OKDAT(D) +ifn $$MCP,pushj p,hwrit2 ;write out uptime as HOURS.xx +ife $$MCP,pushj p,dhmsw ;write out uptime as D!HH:MM:SS + MOVEI T,40. ;ALIGN FOR REASON + PUSHJ P,COLADJ + JRST CRLF + +ifn $$STAT,[ +;;; update STATS line +;;; STATS line looks like: +;STATS fups crftys[crftym]coraos runt[nomax normax newfls newcnt oldfls oldcnt] +;;; where items in [...]'s exist only if $$MCP is on +;;; FUPS is # of file updates +;;; CRFTYS is # of dmnpsh logout's processed (# therefore pushing cruft) +;;; CRFTYM is # of MACSYMA's cruft is pushed for +;;; RUNTIME is total runtime consumed by PUFF +;;; CORAOS is total times core has been grown +;;; NOMAX is total times no MACSYMA's seen +;;; NORMAX is total times no MACSYMA's seen running +;;; NEWFLS is total times NEWFLS is called +;;; NEWCNT is total jobs invalidated by NEWFLS +;;; OLDFLS is total times OLDFLS is called +;;; OLDCNT is total jobs invalidated by OLDFLS + +grvlst: pushj p,sigch ;find significant char + pushj p,untyi ;buffer back the char + move t,column ;remember our column as well + movem t,updtcp ;so we can write it back in the same place + pushj p,numr ;get count of file updates + aos a ;count this update + movem a,updtct ;remember it + movei b,crftys ;# of crufties pushed by logouts + pushj p,addct0 + +ifn $$MCP,[ + movei b,crftym ;count number of crufties pushed by MACSYMA's + pushj p,addct0 +]; END ifn $$MCP, + + movei b,coraos ;update the count of core growings + pushj p,addct0 + + move a,lrunt ;back up + movem a,orunt ;what we wrote out last time + pushj p,sigch ;next significant char + pushj p,untyi ;buffer it back + move t,column ;remember where we got it + movem t,lruntp +ifn $$MCP,pushj p,hread ;get run time from HOURS.xxx +ife $$MCP,pushj p,dhmsr ;get run time from D!HH:MM:SS + movem a,lrunt +ifn $$MCP,[ + pushj p,sigch ;find next entry + pushj p,untyi ;buffer back the char + move t,column ;remember where we got it + movem t,nomaxp + pushj p,hread ;read the number + move b,nomax ;get the count + imuli b,60.*6.*3. ;convert to 1/100'ths of hours + add a,b + movem a,nomaxc ;add in the count + setzm nomax ;restart count + + pushj p,sigch ;find next entry + pushj p,untyi ;buffer back the char + move t,column ;remember where on the line it was found + movem t,normxp + pushj p,hread ;read the number + move b,normax ;get the count + imuli b,60.*6.*3. ;convert to 1/100'ths of hours + add a,b ;add in the count + movem a,normxc ;remember the count for later + setzm normax ;restart count + + movei b,flsnew ;update the count of NEWFLS's we've done + pushj p,addct0 + movei b,cntnew ;update the count of MACSYMA's NEWFLS'ed + pushj p,addct0 + movei b,flsold ;update the count of OLDFLS's we've done + pushj p,addct0 + movei b,cntold ;update the count of MACSYMA's OLDFLS'ed + pushj p,addct0 +]; end $$IFN $$MCP + + setzm column ;start at the LHS + movei tt,[asciz /STATS/] + pushj p,aszw ;write it back out + move t,updtcp ;get where we got the info from + pushj p,coladj ;adjust our column to win + move a,updtct ;get our count of updates + pushj p,numw ;write out new count + movei b,crftys ;# of crufties pushed by logouts + pushj p,addct1 + +ifn $$MCP,[ + movei b,crftym ;count number of crufties pushed by MACSYMA's + pushj p,addct1 +]; END IFN $$MCP, + + movei b,coraos ;update the count of core growings + pushj p,addct1 + + .suset [.rrunt,,a] ;get our runtime + sub a,orunt ;uncount the old + addi a,4166. ;round, + idivi a,8333. ;converting to seconds*30. + add a,lrunt ;count it in with what was there + move t,a ;get copy to round off + addi t,30.*1800./1000. ;round it off + idivi t,30.*3600./1000. ;just like printing and re-reading it will + imul t,[<30.*3600./1000.>*8333.] ;so that we don't accumulate error. + movem t,orunt + move t,lruntp ;get position to write this cruft in + pushj p,coladj +ifn $$MCP,pushj p,hwrit3 ;write with 3 decimal places precision +ife $$MCP,pushj p,dhmsw ;run time in D!HH:MM:SS + +ifn $$MCP,[ + move t,nomaxp + pushj p,coladj + move a,nomaxc ;no-macsyma connect-time count + pushj p,hwrit2 ;record updated count + + move t,normxp + pushj p,coladj + move a,normxc ;no-macsyma run-time count + pushj p,hwrit2 ;record updated count + + movei b,flsnew ;update the count of NEWFLS's we've done + pushj p,addct1 + movei b,cntnew ;update the count of MACSYMA's NEWFLS'ed + pushj p,addct1 + movei b,flsold ;update the count of OLDFLS's we've done + pushj p,addct1 + movei b,cntold ;update the count of MACSYMA's OLDFLS'ed + pushj p,addct1 +]; END IFN $$MCP, + + pushj p,crlf ;terpri + jrst gvlfl1 + +addct0: pushj p,sigch ;find next entry + pushj p,untyi ;buffer back the char + move t,column + movem t,1(b) ;remember where to put it on the line + pushj p,numr ;read the number + addm a,(b) ;add in the count + popj p, ;return + +addct1: move t,1(b) ;get column to hack + pushj p,coladj ;adjust the output column now + move a,(b) ;get the new count + setzm (b) ;restart count + jrst numw ;record updated count +]; END IFN $$STAT, + +6DTCNV: PUSHJ P,6XXMNG ;DAYS SINCE 1 JAN 1901 + SOS A,T + IMULI A,365. + IDIVI T,4 + ADD A,T + PUSHJ P,6XXMNG + ADD A,(T)6DTMNL-1 + PUSHJ P,6XXMNG + ADDI A,-1(T) + POPJ P, + +6DTMNL: ZZ==0 + IRPS L,,31 28 31 30 31 30 31 31 30 31 30 31 + ZZ + ZZ==ZZ+.RADIX 10.,L + TERMIN + +6TMCNV: PUSHJ P,6XXMNG ;SECONDS SINCE MIDNIGHT + MOVE A,T + IMULI A,60. + PUSHJ P,6XXMNG + ADD A,T + IMULI A,60. + PUSHJ P,6XXMNG + ADD A,T + POPJ P, + +6XXMNG: LDB T,[360400,,D] + LDB TT,[300400,,D] + IMULI T,10. + ADD T,TT + LSH D,14 + POPJ P, + +SUBTTL Update user data + +;Update user info from piece of cruft pointed to by Q. + +UPDUSR: SKIPN CF.VAL(Q) + POPJ P, ;already accounted for + SKIPN JNAMEF + JRST UPDUS1 + MOVE A,JNAMEA ;verify that JNAME matches + MOVE B,JNAMEB + MOVE C,JNAMEC + MOVE T,CF.JNM(Q) + PUSHJ P,MATCH + POPJ P, ;no match +UPDUS1: SKIPN ACCNTF + JRST UPDUS2 + MOVE A,ACCNTA ;verify that account matches + MOVE B,ACCNTB + MOVE C,ACCNTC + MOVE T,CF.TNM(Q) + PUSHJ P,MATCH + POPJ P, +UPDUS2: SKIPN HOURSF + JRST UPDUS3 + MOVE T,CF.HOR(Q) ;verify that hour matches + CAML T,FHOUR + CAMLE T,LHOUR + POPJ P, +UPDUS3: MOVE T,CF.CTM(Q) ;update the usage + ADDM T,CTIME + ADDM T,STCTIM ;also update page subtotals + MOVE T,CF.RTM(Q) + ADDM T,RTIME + ADDM T,STRTIM + MOVE T,CF.SWI(Q) + ADDM T,SWAPS + ADDM T,STSWAP +ifn $$mcp,[ + move t,cf.mct(q) ;update the macsyma connect time + addm t,mctime + addm t,stmctm ;update the subtotal + move t,cf.mrt(q) ;update the macsyma run time + addm t,mrtime + addm t,stmrtm ;update the subtotal +];mcp + MOVE T,CF.DAT(Q) + MOVEM T,LODAT + MOVEM T,STLODT + MOVE T,CF.TIM(Q) + MOVEM T,LOTIM + MOVEM T,STLOTM + SETZM CF.VAL(Q) ;don't count this one again + POPJ P, + +;Skip if sixbit in T matches spec in A, B, C. Clobbers A, B, C. + +MATCH: ANDCB B,C ;mask for literally specd chars + XOR A,T ;xor the sixbits + TDNE A,B + POPJ P, ;simply spec'd chars don't match + JUMPE C,POPJ1 ;match! + AND C,T ;chars that gotta be digits or space +REPEAT 6,[ + SETZ B, + LSHC B,6 + JUMPE B,.+4 + CAIL B,'0 + CAILE B,'9 + POPJ P, ;no match +] + JRST POPJ1 ;matches + +SUBTTL Matching Routines + +;Routine to match masked sixbit (in A, B, C) against cruft table. +;For each match, routine after call is called with Q -> piece of cruft. +;Clobbers A, B, Q, R, T, TT plus whatever that routine clobbers. + +UCRUFT: JUMPN B,UCRUF0 ;has stars + JUMPN C,UCRUF0 ;has sharps + JRST FUSER ;easy case + +UCRUF0: MOVEI Q,CRUFT ;Q -> pieces of cruft + ANDCB B,C ;mask for chars literally specd + MOVSI T,(@) + IORM T,(P) + INSIRP PUSH P,A B C Q +UCRUF1: MOVE A,-3(P) + XOR A,CF.UNM(Q) + TDNE A,-2(P) + JRST UCRUF4 ;simply spec'd chars don't match + SKIPN B,-1(P) + JRST UCRUF3 ;match! + AND B,CF.UNM(Q) ;chars that gotta be digits or space +REPEAT 6,[ + SETZ A, + LSHC A,6 + JUMPE A,.+4 + CAIL A,'0 + CAILE A,'9 + JRST UCRUF4 ;no match +] +UCRUF3: PUSHJ P,@-4(P) ;matches, call spec'd routine +UCRUF4: MOVEI Q,CF.LEN ;advance to next piece of cruft + ADDB Q,(P) + CAMGE Q,CRUFTF + JRST UCRUF1 + SUB P,[4,,4] ;done + JRST POPJ1 + +;Routine to do binary search of cruft table for uname in A. +;Calls routine after call with Q -> each matching piece of cruft. +;Clobbers Q, R, T, TT, plus whatever that routine clobbers. + +FUSER: MOVEI T,CRUFT ;T lower limit + MOVE TT,CRUFTF ;TT upper limit +FUSER0: MOVE Q,TT ;Q pointer halfway between + SUB Q,T + JUMPE Q,POPJ1 ;not found + IDIVI Q,CF.LEN*2 ;ensure proper alignment (clobber R) + IMULI Q,CF.LEN + ADD Q,T + CAMN A,CF.UNM(Q) + JRST FUSER2 ;got it. + CAML A,CF.UNM(Q) + JRST FUSER1 + MOVE TT,Q ;go down + JRST FUSER0 + +FUSER1: MOVEI T,CF.LEN(Q) ;go up + JRST FUSER0 + +FUSER2: CAIE Q,CRUFT ;Found one cruft entry for this user. + CAME A,CF.UNM-CF.LEN(Q) ;Look back to see if there are more. + JRST FUSER3 + SUBI Q,CF.LEN + JRST FUSER2 + +FUSER3: MOVSI T,(@) ;Call spec'd routine for all entries for this user. + IORM T,(P) + PUSH P,A + PUSH P,Q +FUSER4: PUSHJ P,@-2(P) + MOVEI Q,CF.LEN + ADDB Q,(P) + CAML Q,CRUFTF + JRST FUSER5 + MOVE A,-1(P) + CAMN A,CF.UNM(Q) + JRST FUSER4 +FUSER5: SUB P,[2,,2] +POPJ1: AOS (P) +CPOPJ: POPJ P, + +SUBTTL I/O Routines + +;Read character into T. Returns -1 at EOF. Keeps track of column position. + +; UNTYI unreads the last character, keeping track of column position +unrch: +untyi: movem t,bbc ;buffer back the character + move t,ocolum ;get the old column number + movem t,column ;it's current now. + move t,bbc ;just in case anyone expects the char to remain + popj p, + +rch: move t,column ;remember this position in case of UNTYI's + movem t,ocolum + skipl t,bbc ;check for buffered back character + jrst [ setom bbc ? jrst rch3] ;get it + sosge inbc + jrst rch1 ;refill input buffer +rch2: ildb t,inbp +rch3: aos column + caie t,^M ;CR? + cain t,^J ;LF? + setzm column ; End of line + CAIE T,^I + POPJ P, + MOVEI T,7 ;tabs + ADD T,COLUMN + TRZ T,7 + MOVEM T,COLUMN + MOVEI T,^I + POPJ P, + +RCH1: MOVE T,[-INBFL,,INBUF] + .IOT INCH,T + MOVEI T,-INBUF(T) ;number of words read + IMULI T,5 ;number of characters + SOJL T,CPOPJ ;if read nothing, eof. + MOVEM T,INBC ;otherwise, set up count + MOVE T,[440700,,INBUF] ;and pointer + MOVEM T,INBP + JRST RCH2 ;and return first character + +;Write character from T + +WCH: SOSGE OUTBC + JRST WCH1 ;no room in output buffer + IDPB T,OUTBP + AOS COLUMN + caie t,^I ;tab? + popj p, ; no, that's all. + movei t,7 ;yes, add another 7 positions + add t,column ;to the position + trz t,7 ;and round down + movem t,column ;to nearest tab stop + movei t,^I ;in case someone really wants it. + popj p, + +WCH1: PUSH P,T + AOSL OUTBC ;skip if no previous buffer + PUSHJ P,WBUF ;dump previous buffer + MOVEI T,5*OUTBFL + MOVEM T,OUTBC + MOVE T,[440700,,OUTBUF] + MOVEM T,OUTBP + POP P,T + JRST WCH + +;Write out the output buffer. Clobbers T. + +WBUF: MOVE T,OUTBP ;pad to end of word + TLNN T,760000 + JRST WBUF1 + MOVEI T,^C + PUSHJ P,WCH + JRST WBUF + +WBUF1: HRLOI T,-OUTBUF(T) + EQVI T,OUTBUF + .IOT OUCH,T + POPJ P, + + +;Routine to read sixbit. +;A gets sixbit, B gets *-mask, C gets #-mask, T gets delimiter. +;Clobbers H, I, J. + +SIXR: SETZB B,C + SETZ A, + MOVE H,[440600,,A] + MOVE I,[440600,,B] + MOVE J,[440600,,C] +SIXR0: PUSHJ P,RCH + CAIN T,"/ + JRST SIXR1 ;slash quotes + CAIN T,"* + JRST SIXR2 ;star matches any + CAIN T,"# + JRST SIXR3 ;sharp matches digits + CAIE T,"_ ;otherwise only letters, digits, underscore, dot allowed + CAIN T,". + JRST SIXR4 + CAIL T,"0 + CAILE T,"z + JRST SIXR9 + CAIL T,"a + JRST SIXR5 + CAILE T,"Z + JRST SIXR9 + CAILE T,"9 + CAIL T,"A + JRST SIXR4 +SIXR9: CAILE T,40 + CAIN T,"= + CAIA + CLBFIL 1,Illegal character in sixbit name. + JUMPN A,CPOPJ ;check for just a star + JUMPN C,CPOPJ + CAMN B,[770000,,000000] + SETO B, ;which should be equivalent to six stars + POPJ P, ;done + +SIXR1: PUSHJ P,RCH +SIXR4: SUBI T,40 +SIXR5: TLNN H,770000 + CLBFIL 1,Name longer than six characters. + IDPB T,H + IBP I + IBP J + JRST SIXR0 + +SIXR2: TLNN H,770000 + CLBFIL 1,Name longer than six characters. + IBP H + SETO T, + IDPB T,I + IBP J + JRST SIXR0 + +SIXR3: TLNN H,770000 + CLBFIL 1,Name longer than six characters. + IBP H + IBP I + SETO T, + IDPB T,J + JRST SIXR0 + +;Advance to next significant char, return it in T. + +SIGCH: PUSHJ P,RCH + CAIE T,40 + CAIN T,^I + JRST SIGCH + POPJ P, + +;Write out from A, B, C. (Opposite of SIXR.) +;Clobbers H, I, J, T, TT. + +SIXW: JUMPN A,SIXW0 ;check for lone star + JUMPN C,SIXW0 + CAME B,[-1] + JRST SIXW0 + WCHI "* + POPJ P, + +SIXW0: MOVE H,[440600,,A] + MOVE I,[440600,,B] + MOVE J,[440600,,C] +SIXW1: TLNN H,770000 + POPJ P, + ILDB T,I ;star? + JUMPN T,SIXW2 + ILDB T,J ;sharp? + JUMPN T,SIXW3 + ILDB T,H + JUMPE T,SIXW4 ;space, handle with char + ADDI T,40 ;ordinary character + CAIN T,"_ ;but maybe needs to be slashified + JRST SIXW6 + CAIE T,". + CAIL T,"0 + CAILE T,"Z + JRST SIXW5 + CAILE T,"9 + CAIL T,"A + JRST SIXW6 +SIXW5: WCHI "/ +SIXW6: PUSHJ P,WCH + JRST SIXW1 + +SIXW2: IBP H + IBP J + WCHI "* + JRST SIXW1 + +SIXW3: IBP H + WCHI "# + JRST SIXW1 + +SIXW4: LDB TT,[360600,,H] ;see if space is embedded or terminal + MOVEI T,1 + LSH T,(TT) + SOS T ;mask for chars not yet processed + TDNE A,T + JRST SIXW7 ;embedded because of ordinary chars to right + TDNN B,T + TDNE C,T + JRST SIXW7 ;embedded because of magic chars to right + POPJ P, ;terminal + +SIXW7: MOVEI T,40 ;embedded space + JRST SIXW5 + +FLNMW: .CALL [ SETZ ;Write filename of input file + 'RFNAME ;Clobber A, B, C, H, I, J, T, TT + MOVEI INCH + MOVEM CLBDEV' + MOVEM CLBFN1' + MOVEM CLBFN2' + SETZM CLBSNM' ] + .LOSE 1000 + SETZB B,C + IRPS NM,CH,[CLBDEV:CLBSNM;CLBFN1 CLBFN2] + MOVE A,NM + PUSHJ P,SIXW + IFSN [CH], WCHI "CH + TERMIN + POPJ P, + +;Read decimal number into A. Buffer-back the delimiter. Clobber T. + +NUMR: SETZ A, +NUMR0: PUSHJ P,RCH + CAIL T,"0 + CAILE T,"9 + JRST UNRCH + IMULI A,10. + ADDI A,-"0(T) + JRST NUMR0 + +;Write decimal number from A. Clobber A, B, T. + +NUMW: MOVMS A ;paranoia + IDIVI A,10. + HRLM B,(P) + SKIPE A + PUSHJ P,NUMW + HLRZ B,(P) + MOVEI T,"0(B) + JRST WCH + +;Adjust to column specified in T, but give at least 2 spaces. +;Clobber T. + +COLADJ: SUB T,COLUMN ;distance to go + CAIGE T,2 + MOVEI T,2 + ADD T,COLUMN ;where to go + PUSH P,T + TRO T,7 + SUB T,COLUMN + LSH T,-3 ;number of tabs needed + JUMPE T,COLAD1 +COLAD0: WCHI ^I + SOJG T,COLAD0 +COLAD1: POP P,T + SUB T,COLUMN ;number of spaces needed + JUMPLE T,CPOPJ +COLAD2: WCHI 40 + SOJG T,COLAD2 + POPJ P, + +;Write asciz from TT. Clobber T, TT. + +ASZW: HRLI TT,440700 +ASZW0: ILDB T,TT + JUMPE T,CPOPJ + PUSHJ P,WCH + JRST ASZW0 + +ifn $$MCP,[ +;;; Read hours.xxx into A as 30'ths of a second. Clobbers T and A + +hread: pushj p,numr ;A gets a number + imuli a,60.*60.*30. ;standard internal time units + pushj p,rch ;T gets delimiter + caig t,40 ;delimiter? + jrst unrch ; buffer it back, and return with no fraction + caie t,". ;had better be "." + clbfil 1,Non "." where decimal point expected in hours.xxx field + pushj p,getdig ;get a digit + popj p, ; delimiter, read no more + imuli t,60.*60.*3. ;first goes in 10'ths position + add a,t ;accumulate in A + pushj p,getdig ;get a digit + popj p, ; delimiter, just return + imuli t,60.*6.*3. ;goes in 100'th of hours position + add a,t + pushj p,getdig ;get a digit, this time + popj p, ; delimiter, just return + imuli t,3600.*30./1000. ;goes in 1000'ths of hours position + add a,t ;accumulate in A + pushj p,rch ;get a character + caig t,40 ;is it a delimiter? + popj p, ;yes, all OK. + clbfil 1,Number too long or garbage in hours.xxx field + +getdig: pushj p,rch ;get another char + caig t,40 ;is it a delimiter? + popj p, + caige t,"0 ; legal digit? + cail t,"9 + caia ; yes + clbfil 2,Garbage in hours.xxx field + subi t,"0 ;convert to number + aos (p) ;skip + popj p, ;return + +;;; HWRIT2 writes time as n.xx Clobbers T, A, B, and C +;;; HWRIT3 writes time as n.xxx Clobbers T, A, B, and C +hwrit2: MOVMS A ;paranoia + addi a,180.*3. ;Round off correction. + movei c,3600.*30./100. ;smallest printing value, for 0 suppression +;falls through +hwrita: idivi a,60.*60.*30. ;convert 30'ths of seconds to hours + push p,b ;save remainder, since NUMW clobbers B + pushj p,numw ;write the number + wchi ". ;decimal point + pop p,a ;recover saved remainder + idivi a,60.*60.*3. ;separate off the big part + pushj p,putdig ;put it out + camge b,c ;Is it aproximately 0?? + popj p, ; yes, don't print any more digits + move a,b ;let's hack the rest + idivi a,60.*6.*3. ;separate off the 100'ths hours + pushj p,putdig ;put out this digit + camge b,c ;is the rest effectively 0? + popj p, ; yes, don't print any more digits + move a,b ;B has last digit + idivi a,3600.*30./1000. ;final convertion to 1000'th of hour from secs + jrst putdig ;write out last digit + +hwrit3: movms a ;paranoia, inherited from MOON + addi a,18.*3. ;round, don't truncate! + movei c,3600.*30./1000. ;smallest printing val for zero supression + jrst hwrita ;write out all but last digit + +putdig: movei t,"0(a) ;turn A into ascii digit + jrst wch ;and write out the digit + +] ;END IFN $$MCP, + +IFE $$MCP,[ +;Read DD!HH:MM:SS into A. Buffer-back delimiter. Clobber A, B, C, T. +DHMSR: SETZB B,C ;B seconds from HH:MM:SS, C days +DHMSR0: PUSHJ P,NUMR ;A gets a number + PUSHJ P,RCH ;T gets its delimiter + CAIN T,"! + JRST DHMSR1 + CAIN T,": + JRST DHMSR2 + PUSHJ P,UNRCH + IMULI C,24.*60.*60. + ADD A,C + IMULI B,60. + ADD A,B + imuli a,30. ;convert to seconds*30. + POPJ P, +DHMSR1: MOVE C,A + JRST DHMSR0 +DHMSR2: IMULI B,60. + ADD B,A + JRST DHMSR0 + +;Write DD!HH:MM:SS from A. Clobber A, B, T. +DHMSW: MOVMS A ;paranoia + SETZM DHMSWF' ;frob-typed flag + idivi a,30. ;convert to seconds + IDIVI A,24.*60.*60. ;seperate days from HHMMSS + JUMPE A,DHMSW0 ;suppress days + PUSH P,B + PUSHJ P,NUMW + WCHI "! + POP P,B + SETOM DHMSWF +DHMSW0: MOVE A,B + IDIVI A,60.*60. + SKIPN DHMSWF + JUMPE A,DHMSW1 + PUSH P,B + PUSHJ P,NUM2W + WCHI ": + POP P,B + SETOM DHMSWF +DHMSW1: MOVE A,B + IDIVI A,60. + SKIPN DHMSWF + JUMPE A,DHMSW2 + PUSH P,B + PUSHJ P,NUM2W + WCHI ": + POP P,B + SETOM DHMSWF +DHMSW2: MOVE A,B +NUM2W: SKIPN DHMSWF ;If a frob already typed, write number with two digits. + JRST NUMW + IDIVI A,10. + WCHI "0(A) + WCHI "0(B) + POPJ P, +]; END IFE $$MCP, + + +;Read YY.MM.DD into A as SIXBIT/YYMMDD/. Clobber T, B, C. Buffer back delimiter. + +DATR: SKIPA C,[".] + +;Read HH:MM:SS into A as SIXBIT/HHMMSS/. Clobber T, B, C. Buffer back delimiter. + +TIMR: MOVEI C,": + SETZ A, + MOVE B,[440600,,A] +TIMR0: PUSHJ P,RCH + CAMN T,C + JRST TIMR0 + CAIL T,"0 + CAILE T,"9 + JRST TIMR1 + SUBI T,40 + TLNN B,770000 + CLBFIL 1,Date/Time too long. + IDPB T,B + JRST TIMR0 + +TIMR1: MOVE B,A + AND B,[606060606060] + CAME B,[202020202020] + CLBFIL 1,Date/Time short or garbaged. + JRST UNRCH + +;Write SIXBIT/YYMMDD/ in A as YY.MM.DD. Clobber T, B, C. + +DATW: SKIPA C,[".] + +;Write SIXBIT/HHMMSS/ in A as HH:MM:SS. Clobber T, B, C. + +TIMW: MOVEI C,": + MOVE B,[440600,,A] +TIMW0: ILDB T,B + ADDI T,40 + PUSHJ P,WCH + ILDB T,B + ADDI T,40 + PUSHJ P,WCH + TLNN B,770000 + POPJ P, + MOVE T,C + PUSHJ P,WCH + JRST TIMW0 + +SUBTTL System message logging + +;This looks for SYSMSG messages starting with: +; "DSK: " +; "MEMORY: " +;and files them in the file DRAGON; SYSMSG LOG +;Clobbers all registers, uses OUCH + +DSKLOG: SETOM DSKLGF ;Flag file not open yet + SETOM OUTBC ;Initialize output buffer routine + .SUSET [.SIDF1,,[%PIRLT]] ;Defer real-time ints + MOVEI TT,8 ;Compute number of words in SYSMBF + LSH TT,@SYSMLNG + MOVEM TT,SYSMBL + SUBI TT,1 + MOVEM TT,SYSMBM +DSKLG0: MOVE TT,@SYSMPT ;Last message generated by system + CAMG TT,SYSMPU + JRST DSKLGX ;No new messages + SUB TT,SYSMBL + CAMLE TT,SYSMPU + MOVEM TT,SYSMPU ;Got behind, skip to catch up + MOVEI A,8 + ADDB A,SYSMPU + AND A,SYSMBM ;Index in SYSMBF of message to do + ADD A,SYSMBF ;Address in system of message + + HRRZ B,(A) ; Get pointer to ascii message + MOVE TT,SYCORE(B) ; Get first 5 characters + CAMN TT,[ASCII/DSK: /] + JRST DSKLGA ; Go log DSK: message + CAME TT,[ASCII/MEMOR/] + JRST DSKLG0 ; Not relevant, ignore + MOVE TT,SYCORE+1(B) ; Get next 5 characters + TRZ TT,77777 ; Reduce to next 3 characters + CAME TT,[ASCII/Y: /] + JRST DSKLG0 ; Not relevant, ignore + ; Go log MEMORY: message +DSKLGA: AOSN DSKLGF ;Open file if necessary + PUSHJ P,DSKLGO + WCHI 15 ;crlf + WCHI 12 + .RDATE TT, ;Time stamp + PUSHJ P,6BTW + WCHI 40 + .RTIME TT, + PUSHJ P,6BTW + WCHI 40 + WCHI 40 + ADD B,[440700,,SYCORE] ;bp to asciz string to type + HLLZ D,(A) ;Get arg mode types +DSKLG1: ILDB T,B + JUMPE T,DSKLG2 ;end + CAIGE T,10 + JRST DSKLG3 ;insert that many arguments + PUSHJ P,WCH + JRST DSKLG1 + +DSKLG2: WCHI 40 + PUSHJ P,DSKLG4 + JRST DSKLG0 + JRST DSKLG2 + +DSKLG3: PUSH P,T ;Number of args to print +DSKL3A: PUSHJ P,DSKLG4 + JFCL + WCHI 40 ;Space after each arg + SOSLE (P) + JRST DSKL3A + SUB P,[1,,1] + JRST DSKLG1 + +;Display next arg, using A and D. +DSKLG4: MOVEI C,0 + LSHC C,3 ;Pull arg-type out of D + JUMPE C,CPOPJ ;No more args, return with no skip + AOS (P) ;Normally skips, i.e. more args exist + AOS A + MOVE TT,(A) ;Get arg + XCT .(C) + JRST DSKLG5 ;1 Octal + JRST DSKLG6 ;2 Decimal + JRST DSKLG6 ;3 Decimal with commas + POPJ P, ;4 crlf (ignore) + POPJ P, ;5 not used + JRST 6BTW ;6 Sixbit + JRST DSKLG7 ;7 Asciz + +DSKLG7: ADDI TT,SYCORE + JRST ASZW + +DSKLG5: TLNN TT,-1 + JRST DSKLG9 + PUSH P,TT + HLRZS TT + PUSHJ P,DSKLG9 + WCHI ", + WCHI ", + POP P,TT + HRRZS TT +DSKLG9: SKIPA C,[8] +DSKLG6: MOVEI C,10. + MOVE T,TT +DSKLG8: IDIV T,C + HRLM TT,(P) + SKIPE T + PUSHJ P,DSKLG8 + HLRZ T,(P) + ADDI T,"0 + JRST WCH + +;Routine to open the disk log file +DSKLGO: .CALL [ SETZ + SIXBIT/OPEN/ + JFFO TT ;error code + [100000+.BAO,,OUCH] ;Write over + [SIXBIT/DSK/] + [SIXBIT/SYSMSG/] + [SIXBIT/LOG/] + SETZ SNAME ] + CAIA + JRST DKLGO1 + CAIE TT,%ENSFL + JRST [ SUB P,[1,,1] + JRST DSKLGX ] ;Give it up + .CALL [ SETZ + SIXBIT/OPEN/ + [.BAO,,OUCH] + [SIXBIT/DSK/] + [SIXBIT/SYSMSG/] + [SIXBIT/LOG/] + SETZ SNAME ] + JRST [ SUB P,[1,,1] + JRST DSKLGX ] ;Give it up +DKLGO1: .CALL [ SETZ ;Seek to eof + 'FILLEN + MOVEI OUCH + SETZM TT ] + .LOSE %LSSYS + .ACCESS OUCH,TT + POPJ P, + +;Print next arg +;Sixbit output from TT +6BTW: MOVEI T,0 + LSHC T,6 + ADDI T,40 + PUSHJ P,WCH + JUMPN TT,6BTW + POPJ P, + +;Exit from DSKLOG +DSKLGX: SKIPL OUTBC ;If any buffered output, send it + PUSHJ P,WBUF + .CLOSE OUCH, + .SUSET [.SADF1,,[%PIRLT]] ;Reenable real-time ints + POPJ P, + +ifn $$MCP,[ +;;; Access a shared page of MACSYMA + +maxget: syscal open,[%CLBIT,,.uii ;access MACSYMA + %climm,,maxch ;on it's very own channel + [sixbit /SYS/] + [sixbit /TS/] + [sixbit /MACSYM/]] + .lose %lsfil + syscal corblk,[%clbit,,%cbndr + %climm,,0 + %climm,,%jself + %climm,,maxpag + %climm,,maxch + %climm,,maxshr] ;maxshr is page of file shared with MACSYMA + .lose %lsfil + .close maxch, + popj p, + + +;;; find all MACSYMA's and account for them +;;; This should only be called with interrupts defered +MAXSCN: pushj p,maxmrk ;mark all the MACSYMA's + jrst maxswp ;scan and push all old macsymas + +maxlog: movsi j,-ntrees +maxlg1: skipn mx.xun(j) ;is there one there? + jrst maxlg9 ; nope, nothing further to do + pushj p,mxpsh1 ;push the cruft, but don't reset it + setzm mx.ctm(j) ;don't count connect time twice +maxlg9: aobjn j,maxlg1 ;for all MACSYMA's + popj p, ;don't do anything yet + +;;; This routine is called every 100'th of an hour and finds all jobs with +;;; a page sharing with our MAXPAG, and if that job is already under +;;; survelance, (as determined by the same XUNAME, and runtime > +;;; than previous runtime) AOS's the connect time, and updates the run time +;;; If the slot is filled with a different job, it is pushed onto cruft +;;; table. The flag half of MX.CTM is then set to -1 for new entries, and +;;; 1 for new entries, for the sake of detecting timing screws that leave +;;; you in another page's circular list. If this condition is detected, +;;; all new entries are purged in the sweep phase. +;;; +;;; The sweep routine, which is called after the mark phase, and clears +;;; LH(MX.CTM) and pushes cruft for MACSYMA's that have disappeared, and +;;; deletes entries not active. + +MAXMRK: move j,ruind ;in ourself + syscal cortyp,[%climm,,%jsnum(j) ;start in our very own + %climmm,,maxpag ;MACSYMA page + %clout,,t ;ignore type of page + %clout,,j ;job + %clout,,i ;page# in job + %clout,,t] ;determines non-shared page + .lose %lssys ; FOOBAR + hrrz t,t ;flush left-half bits! + sosle t ;any sharers? + jrst markl1 ; yes, trace down that chain + +ifn $$stat,aos nomax ;nope! Count this event! + + popj p, ;but don't try to count MACSYMA's + +marklp: syscal cortyp,[%climm,,%jsnum(j) ;job we are hacking + i ;page in job + %clout,,t ;Ignore type of page + %clout,,j ;job + %clout,,i ;page # in job + %clout,,t] ;determines non-shared page + jrst newfls ; lost chain somewhere, restart + hrrz t,t ;flush left-half bits! + sojle t,newfls ;if T is 1 or zero, no sharers, lost chain +markl1: camn j,ruind ;is it us? + popj p, ; yes, end of circle + jumpe j,newfls ;paranoia + movei r,(j) ;move pointer to R so we can hack abs addrs + imul r,lublk ;make absolute pointer + + hlre tt,mx.ctm(j) ;have we already looked at this job? + jumpl tt,newfls ; YES! Invalidate new jobs! + jumpn tt,oldfls ; YES! Invalidate ALL jobs!!!!!! Lose!!! + + pushj p,smjobp ;check to be sure it's the same job + jrst markn ; not same! or gone (0 -=> b) + + movei tt,1 ;note that this job was already there + hrlm tt,mx.ctm(j) ;marked! + jrst marklp ;loop til no more jobs in chain + +markn: jumpe b,newfls ;if b is 0, retry + hrros mx.ctm(j) ;mark this job as new + jrst marklp ;keep on marking + +;; come here to flush all new entries and retry mark operation +newfls: movsi j,-ntrees ;for all trees + +ifn $$STATS,aos flsnew ;count the number of times we do this + +newfl1: hlre t,mx.ctm(j) ;get the flag + skipge t ;if it's new + pushj p,maxrst ; reset the entry + +ifn $$STATS,[ + skipge t ;if it's new + aos cntnew ; count this for our stats +]; END IFN $$STATS, + + aobjn j,newfl1 ;for all trees + jrst maxmrk ;restart + +;; come here to flush all entries and retry mark operation +oldfls: movsi j,-ntrees ;for all tress + +ifn $$STATS,aos flsold ;count the number of times this gets done + +oldfl1: +ifn $$STATS,[ + skipn mx.xun ;if there's anything there + aos cntold ; count it as being flushed +]; END IFN $$STATS, + + pushj p,maxrst ;reset the entry (always, out of paranoia) + aobjn j,oldfl1 ;play it again. + jrst maxmrk ;restart + + +;;;; the sweep phase. Pushes dead jobs, unmarks. + +maxswp: movsi j,-ntrees ;for all MACSYMA's + +ifn $$STAT,setzm rmaxfl ;flag to notice if there are no running maximas + +maxsw0: hlre t,mx.ctm(j) ;Get the marking + hrrzs mx.ctm(j) ;unmark it + skipn tt,mx.xun(j) ;is there a MACSYMA in this slot? + jumpe t,maxsw9 ; no macsyma, no mark, ignore the slot + jumpe tt,maxsw4 ; no macsyma, marked. Initialize + jumpe t,maxsw6 ; MACSYMA, no mark, just push old MACSYMA. + jumpg t,maxsw4 ; MACSYMA, old MARK + pushj p,maxpsh ; MACSYMA, new marked. Push first. + +maxsw4: movei r,(j) ;get pointer into system for this job. + imul r,lublk ;convert to system pointer + move t,@ustp ;get info on run/stopped state + pushj p,smjobp ;is this the same job? Get info + jumpn tt,maxsw6 ; no, don't hack this entry + jumpe b,maxsw5 ;job gone, don't hack this entry, push it + + movem b,mx.xun(j) ;remember who you are + + tlnn t,busrc ;Is it running? + aos mx.ctm(j) ; count this connect time + tlnn t,busrc ;is it running? + setom rmaxfl ; note that we found one + movem a,mx.rtm(j) ;save the runtime + + movei tt,9. ;default hour is 9. am + syscal rqdate,[%clout,,t] + jrst [movem tt,mx.hor(j) ;system doesn't know time, assume 9 + jrst maxsw9] + hrrs t + idivi t,2.*60.*60. ;convert to hour of day + movei tt,(t) ;get in TT + movem tt,mx.hor(j) + + jrst maxsw9 ;already pushed entry, if any + +maxsw5: skipe mx.xun(j) ;if there is a job in this slot +maxsw6: pushj p,maxpsh ; Push this entry +maxsw9: aobjn j,maxsw0 ;for all MACSYMA's + +ifn $$stat,[ + skipn rmaxfl ;were there any running MACSYMA's? + aos normax ; nope, count this event +]; end ifn $$stat, + + popj p, ;return + + +;;; SMJOBP skips if job pointed to by J is the same one recorded earlier +;;; assumes R is already set to LUBLK* +;;; as a side effect, it returns runtime in A and XUNAME in B. +;;; if the job is gone, it returns 0 in B +;;; Does not clobber T or TT !! + +smjobp: move a,@utrntm ;get runtime for this user + skipn b,@xuname ;get XUNAME for this user + move b,@uname ; Or UNAME if no XUNAME + skipn @uname ;paranoia, has the job disapeared? + setz b, ; if UNAME is 0, XUNAME should be too! + jumpe b,cpopj ;Paranoid of timing screws + + skipn mx.xun(j) ;Is there already a job in that slot? + popj p, + came b,mx.xun(j) ;is it this same job? + popj p, ; No, gotta push it first + camge a,mx.rtm(j) ;is it the same job? + popj p, ; No, gotta push it first + jrst popj1 ;same job! + +;;; push the MACSYMA entry pointed to by J onto the cruft table and reset it. + +maxpsh: pushj p,mxpsh1 ;push the cruft +maxrst: setzm mx.xun(j) ;clear out the XUNAME + setzm mx.ctm(j) ;and connect time + setzm mx.rtm(j) ;and runtime + setzm mx.ort(j) ;and old runtime + setzm mx.hor(j) ;he didn't log in at a time yet! + popj p, ;done, return + + +mxpsh1: + +ifn $$STAT,aos crftym ;count number of times pushed these + + pushj p,getcor ;allocate a crufty + popj p, ; no core + move t,mx.xun(j) ;get the name + movem t,cf.unm(h) ;and name the crufty + move t,[sixbit /HACTRN/] ;pretend it's a HACTRN + movem t,cf.jnm(h) + setzm cf.ctm(h) ;connect time is counted elsewhen + setzm cf.rtm(h) ;similarly the + setzm cf.swi(h) ;other tree-total resources. + setzm cf.tnm(h) ;similarly, since TRMNAM isn't used now. + hrrz t,mx.ctm(j) ;remember MACSYMA connect time + imuli t,30.*3600./100. ;units of 1/100'th of an hour to seconds*30. + movem t,cf.mct(h) + move t,mx.rtm(j) ;remember MACSYMA run time + sub t,mx.ort(j) ;this much has been counted already + addi t,4166. ;round, + idivi t,8333. ;converting to seconds*30. + movem t,cf.mrt(h) ;and put it into the cruft + addi t,30.*1800./1000. ;round it off + idivi t,30.*3600./1000. ;just like printing and re-reading it will + imul t,[<30.*3600./1000.>*8333.] ;so that we don't accumulate error. + addm t,mx.ort(j) ;remember we've counted this much + pushj p,rdatim ;TT gets date, T gets time + movem tt,cf.dat(h) ;remember date + movem t,cf.tim(h) ;time + setom cf.val(h) ;etc. + popj p, ;return + +]; END IFN $$MCP, + + +SUBTTL batch job launcher + +;;;Call this routine with a first file name in A. Checks for files on +;;;DRAGON with that first file name, which it then loads and launches. + +if1, .insrt system;fsdefs + +batdir: sixbit /dragon/ ;directory to check for batch jobs. + +batch: syscal open,[[.bii,,batdsk] ? [sixbit /dsk/] + [sixbit /.file./] ? [sixbit /(dir)/] ? batdir] + .lose %lssys + move tt,[-2000,,batufd] + .iot batdsk,tt + .close batdsk, + move t,batufd+udnamp +batch1: cail t,2000 + jrst batch3 + came a,batufd+unfn1(t) + jrst batch2 + syscal open,[[.uii,,batdsk] ? [sixbit /dsk/] + a ? batufd+unfn2(t) ? batdir] + jrst batch2 + syscal open,[[.bio,,batusr] ? [sixbit /usr/] + movei 0 ? batufd+unfn2(t)] + jrst batch2 + syscal load,[movei batusr ? movei batdsk] + jrst batch2 + .iot batdsk,tt + hrrz tt,tt + .uset batusr,[.supc,,tt] + syscal disown,[%clbit,,5 ? movei batusr] + jfcl +batch2: addi t,lunblk + jrst batch1 + +batch3: .close batdsk, + .close batusr, + popj p, + +SUBTTL Variables, etc. + + VARIABLES + +;Variables into which a line from accounting file is copied + +LVRBEG:: +UNAMEA: 0 ;sixbit of uname +UNAMEB: 0 ;* mask for uname +UNAMEC: 0 ;# mask for uname +JNAMEA: 0 ;sixbit of jname +JNAMEB: 0 ;* mask for jname +JNAMEC: 0 ;# mask for jname +JNAMEF: 0 ;jname present flag +ACCNTA: 0 ;sixbit of accnt +ACCNTB: 0 ;* mask for accnt +ACCNTC: 0 ;# mask for accnt +ACCNTF: 0 ;account present flag +FHOUR: 0 ;first hour +LHOUR: 0 ;last hour +HOURSF: 0 ;hours present flag +CTIME: 0 ;connect time in seconds*30. +CTIMEP: 0 ;column position of .. + 1 +RTIME: 0 ;run time in seconds*30. +RTIMEP: 0 ;column position of .. + 1 +SWAPS: 0 ;number of swap ins +SWAPSP: 0 ;column position of .. + 1 + +ifn $$MCP,[ +mctime: 0 ;macsyma connect time in seconds*30. +mctimp: 0 ;column position of .. + 1 +mrtime: 0 ;macsyma run time in seconds*30. +mrtimp: 0 ;column position of .. + 1 +]; END IFN $$MCP, + +LODAT: 0 ;logout date +LODATP: 0 ;column position of .. + 1 +LOTIM: 0 ;logout time +LOTIMP: 0 ;column position of .. + 1 +COLUMN: 0 ;current column position +OCOLUM: 0 ;previous column position (for sake of TAB's) +LVREND:: + +;I/O Routines' Variables + +INBC: 0 ;input bytes available +INBP: 0 ;input byte pointer +OUTBC: 0 ;output bytes left in buffer +OUTBP: 0 ;output byte pointer +BBC: -1 ;.GE. 0 => buffered back character + +INBFL==200 +INBUF: BLOCK INBFL ;input buffer +OUTBFL==200 +OUTBUF: BLOCK OUTBFL ;output buffer + +;Variables for error routine + +NERRS: 0 ;number of errors (index into ERRBFZ, ERRBFL) +LERRBF==40 +ERRBFL: BLOCK LERRBF ;line number +ERRBFZ: BLOCK LERRBF ;asciz message +ERRBFA: BLOCK LERRBF ;uname being hacked +ERRBFB: BLOCK LERRBF ;.. +ERRBFC: BLOCK LERRBF ;.. +LINENO: 0 ;current line number +INTJPC: 0 ;JPC at TSINT +BUGJPC: 0 ;JPC at BUGCHK +BUGACS: BLOCK 20 ;ACs at BUGCHK +BUGMSG: BLOCK 10 ;DMNPOP copies each message into here for benefit of BUGCHK + +;Variables for batch job launcher + +batufd: block 2000 ;binary MFD of directory to search for batch jobs. + +;Variables for file updater etc. + +CHKALL: 1,, ;non-zero => check all lines for garbage, not just ones being updated. + ;LH is modified by program; RH is a debugging switch. + ;assembled non-zero so will check whole file when first starting up. +UPDATR: 0 ;name of person who last updated the file. +UPDATJ: 0 ;jname +CLIFLG: 0 ;0 normal, -1 do initial file update, 1 waiting for CLI completion. +DWNTIM: 0 ;time system went down. + +DRANDF: 0 ;non-zero => delete useless randoms +RANDF: 0 ;non-zero => currently in random users section. +TOTLF: 0 ;non-zero => currently in totals section. +STOTLF: 0 ;non-zero => next line is subtotals. +LASDAT: 0 ;sixbit date file last updated +YEARF: 0 ;nonzero => year has just ticked over +MONTHF: 0 ;nonzero => month has just ticked over +DAYF: 0 ;nonzero => day has just ticked over +MNTHLF: 0 ;nonzero => doing monthly reset processing +STCTIM: 0 ;subtotal connect time +STRTIM: 0 ;subtotal run time +STSWAP: 0 ;subtotal swaps +IFN $$MCP,[ +stmctm: 0 ;subtotal MACSYMA connect time +stmrtm: 0 ;subtotal MACSYMA run time +]; END IFN $$MCP, + +STLODT: 0 ;subtotal logout date +STLOTM: 0 ;subtotal logout time +GTCTIM: 0 ;grand total connect time +GTRTIM: 0 ;grand total run time +GTSWAP: 0 ;grand total swaps + +IFN $$MCP,[ +gtmctm: 0 ;grand total MACSYMA connect time +gtmrtm: 0 ;grand total MACSYMA run time +]; END IFN $$MCP, + ;don't change order of next 6 items +OKDAT: -1 ;sixbit date last seen this execution of dragon +OKTIM: -1 ;sixbit time ditto +OKTMUP: -1 ;seconds*30. of up-time +NOKDAT: 0 ;last date from file +NOKTIM: 0 ;.. +NOKTMU: 0 ;.. + +LOTOLD: BLOCK 5 ;read from file into here + 0 +LOTNEW: ASCII\UNAME MM/DD/YY HH:MM:SS +\ ;build new in here +IFN .-LOTNEW-5, .ERR LOTNEW loses + +;dmn-push message from system for login + +LI.==,,-1 +LI.TIM==0 ;FIRST WORD IS TIME IN 30THS +LI.IDX==1 ;RH USER INDEX + LI%COD==10000 ;LH IS THIS CODE +LI.UNM==2 ;UNAME +LI.JNM==3 ;JNAME +LI.TNM==4 ;TRMNAM + +;dmn-push message from system for logout + +LO.==,,-1 +LO.TIM==0 ;FIRST WORD IS TIME IN 30THS +LO.IDX==1 ;RH USER INDEX + LO%COD==20000 ;LH IS THIS CODE +LO.UNM==2 ;UNAME +LO.JNM==3 ;JNAME +LO.RTM==4 ;RUN TIME IN 4.069 MICROSECOND UNITS +LO.SWI==5 ;SWAP-IN REQUESTS + +;Fake logout message used at shutdown + +FAKMSG: + 0 ;LO.TIM + LO%COD,, ;LO.IDX + 0 ;LO.UNM + 0 ;LO.JNM + 0 ;LO.RTM + 0 ;LO.SWI + +;All stuff referenced frequently by DMNPOP etc. should be after this point. + +CONST.: CONSTANTS + +;Cruft for each logged in tree + +NTREES==171 ;SHOULD BE ENOUGH (BETTER BE MORE THAN MAXJ) +TR.UNM: BLOCK NTREES ;UNAME, 0 IF SLOT EMPTY +TR.JNM: BLOCK NTREES ;TOP JNAME +TR.TNM: BLOCK NTREES ;TRMNAM AT LOGIN +TR.XUN: BLOCK NTREES ;XUNAME +TR.TIM: BLOCK NTREES ;TIME AT LOGIN (FOR COMPUTING CONNECT) + +;Unless we miss a dmn-push, nothing can go away or change +;its name without the system saying so. Trees can appear +;without the system saying so if they are created by disowning; +;in that case we just won't charge connect time. + +IFN $$MCP,[ +mx.xun: block ntrees ;UNAME, 0 if slot empty +mx.ctm: block ntrees ;,, (flag is used to mark MACSYMAs + ; found on given scan; the count -=> connect time) +mx.rtm: block ntrees ;runtime of this MACSYMA +mx.ort: block ntrees ;runtime of this MACSYMA which has already been recorded +mx.hor: block ntrees ;hour this MACSYMA was started, for HOURS= +]; END IFN $$MCP, + +;Cruft pushed for logged out trees (at end of core) + +CF.==,,-1 + +CF.UNM==0 ;XUNAME (0 MARKS END OF CRUFT) +CF.JNM==1 ;JNAME +CF.TNM==2 ;TRMNAM (ACCOUNT) +CF.HOR==3 ;HOUR OF THE DAY LOGGED IN (0-23.) +CF.CTM==4 ;CONNECT TIME IN SECONDS*30. +CF.RTM==5 ;RUN TIME IN SECONDS*30. +CF.SWI==6 ;# SWAPINS + +ifn $$MCP,[ +CF.MCT==7 ;# of times this MACSYMA was runable +CF.MRT==10 ;run time this MACSYMA observed to use +CF.DAT==11 ;SIXBIT DATE OF LOGOUT +CF.TIM==12 ;SIXBIT TIME OF LOGOUT +CF.VAL==13 ;VALID FLAG (0 => HAS BEEN PUT INTO ACCT FILE) +CF.LEN==14 ;# WDS/CRUFTY +]; END IFN $MCP, + +ife $$MCP,[ +CF.DAT==7 ;SIXBIT DATE OF LOGOUT +CF.TIM==10 ;SIXBIT TIME OF LOGOUT +CF.VAL==11 ;VALID FLAG (0 => HAS BEEN PUT INTO ACCT FILE) +CF.LEN==12 ;# WDS/CRUFTY +]; END IFE $MCP, + +;data +ruind: 0 ;OUR user index + +;timers +dmpcnt: -31 ;count till time to dump +dmpinv: -31 ;# of clock cycles between file updates (25. = 15 minutes) +maxcnt: -1 ;count till time to do acounting update on MACSYMAs +maxinv: -1 ;count of ticks per 36. second period +rltinv: 60.*36. ;36. seconds between ints, normally. + +CRUFTP: CRUFT ;points at first unused entry in cruft table. +CRUFTF: CRUFT ;fence. stuff below this is getting updated into file. +CRUFTE: CRUFTZ ;points at highest loc+1 allocated for cruft table. + ; which had better be a page boundary. + + +ifn $$STAT,[ +;; internal statistics + +updtct: 0 ;count of file updates +updtcp: 0 ;position of above on line +crftys: 0 ;# of pieces of cruft pushed by logout dmnpush +crftsp: 0 ;position of above on line +lrunt: 0 ;last recorded runtime +lruntp: 0 ;position of above on line +orunt: 0 ;runtime consumed so far in this job +coraos: 0 ;# of times we've grown core. +coraop: 0 ;position of above on line + +ifn $$MCP,[ +rmaxfl: 0 ;flag to notice no running MACSYMA's seen + +crftym: 0 ;# of pieces of cruft pushed for MACSYMA's +crftmp: 0 ;position of above on line +nomax: 0 ;# of times no MACSYMA's seen +nomaxc: 0 +nomaxp: 0 ;position of above on line +normax: 0 ;# of times no running MACSYMA's seen +normxc: 0 +normxp: 0 ;position of above on line +flsnew: 0 ;# of times we've NEWFLS'd +flsnwp: 0 ;position of above on line +cntnew: 0 ;# of MACSYMA's we've NEWFLS'd +cntnwp: 0 ;position of above on line +flsold: 0 ;# of times we've OLDFLS'd +flsolp: 0 ;position of above on line +cntold: 0 ;# of MACSYMA's we've OLDFLS'd +cntolp: 0 ;position of above on line +]; END IFN $$MCP, +]; END IFN $$STAT, + + +;Pointers to relevant system symbols + +DEDTIM: 0 ;<0 system down. 0 Up. Otherwise time till death. +TIME: 0 ;30ths since system up. +USRHI: 0 ;index of highest user +. +LUBLK: 0 ;length of user variables block. +UNAME: 0 ;user name. +XUNAME: 0 ;user's intended uname +JNAME: 0 ;job name. +SUPPRO: 0 ;superior pointer. +USTP: 0 ;run/stop flag +UTRNTM: 0 ;user run time. +USIPRQ: 0 ;user swapin requests. +TRUNTM: 0 ;run time of inferiors minus previously-logged. +TSIPRQ: 0 ;swapin requests of inferiors minus previously-logged. + +DMNBC: 0 ;AOS'ed each time something is put in the buffer, before +DMNBD: 0 ;AOS'ed each time something is put in the buffer, after +DMNBF: 0 ;the buffer +DMNBFE: 0 ;the end of the buffer +DMNBEL: 0 ;# words per message + +LDMNBD: 0 ;last value of DMNBD seen +DMNBSZ: 0 ;number of frobs that fit in the buffer + +SYSMPT: 0 ;Pointer to index of message most recently inserted in SYSMBF +SYSMLNG:0 ;log(2) of number of 4-word entries in SYSMBF +SYSMBF: 0 ;Pointer to SYSMSG table in the system +SYSMBL: 0 ;Number of words in SYSMBF +SYSMBM: 0 ;That minus one (mask) +SYSMPU: 0 ;Index of last message processed +DSKLGF: 0 ;-1 means file not opened yet in DSKLOG + +;Cruft Table Starts Here + +CRUFT: -1 +CRUFTZ==&<776000> ;address of first additional cruft page. +crfmrg==20. ;ask for update this many crufties from full +crfsiz==10. ;ten pages of cruft before panic dump + +maxpag==176 ;page for sharing with MACSYMA +maxshr==60 ;page of SYS:TS MACSYM to share with + +CMPAGE=376000 ;Communication page, see CLIINT. +SYCORE=400000 ;Upper Core is mapped into absolute. + +END GO