diff --git a/READaux b/READaux new file mode 100644 index 0000000..7697c67 --- /dev/null +++ b/READaux @@ -0,0 +1,78 @@ +/* READaux - README file for KLH10 Auxiliary Distribution +*/ +/* $Id: klh10aux.rdm,v 2.1 2001/11/10 10:38:16 klh Exp $ +*/ +/* Copyright © 2001 Kenneth L. Harrenstien +** +** This file is part of and describes the "Auxiliary Distribution" +** package, built and released as a companion to the KLH10 Distribution. +** The legal text is contained below. +*/ + + ---------------------------- + +The KLH10 Auxiliary Distribution consists of all the components (both +software and documentation) residing in the "contrib" and "run" +directories of a typical installation of the KLH10 Distribution. + +The KLH10 Distribution license does NOT apply to these components. +They are derived from several sources, each of which may have its own +licensing terms. They are included solely for the convenience of +users, and in order to avoid licensing conflicts have been made +available in the form of a separate "Auxiliary Distribution" package. +They are subject to removal if their inclusion causes any legal +problems. + +The Auxiliary Distribution package includes the following specific +components: + +[1] PDP-10 software (bootstrap and diagnostic binaries) from Digital + Equipment Corporation (now Compaq Corporation). These may be used + only with a valid Digital license such as the "Home Hobbyist License" + (see ). + The specific components are identified by various README files in + the following subdirectories. + + run/dfkfb/ - Digital (KL10) DFKFB timing test diagnostic binary + run/klnic/ - Digital (KL10 SRI-NIC) bootstrap binaries + run/klt10/ - Digital (KL10 TOPS-10) bootstrap binaries + run/klt20/ - Digital (KL10 TOPS-20) bootstrap binaries + run/kst10/ - Digital (KS10 TOPS-10) bootstrap binaries + run/kst20/ - Digital (KS10 TOPS-20) bootstrap binaries + + +[2] PDP-10 software derived from the MIT ITS systems. These are + believed to be usable on terms similar to those of the GNU Public + License. + The specific components are listed in the file "run/ksits/README". + + run/ksits/ - MIT (KS10 ITS) system binaries + + +[3] Utility software from other contributors, where terms were not + specifically stated but are believed to be similar to those of + the "BSD" style licenses (e.g. FreeBSD, NetBSD). + More detail is provided in the file "contrib/README" and the + individual subdirectories. + + contrib/supdup/ - Unix SUPDUP client and server + contrib/read20/ - Unix DUMPER tape image reader + + +Disclaimer: + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL KENNETH L. HARRENSTIEN BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ---------------------------- + +To reiterate: If there is any likelihood that your intended use may +violate any of the licensing terms of the separate components, you +should NOT use them. If any of the original copyright holders object +to this packaging, I will remove the offending components or simply +stop providing the Auxiliary Distribution altogether. diff --git a/contrib/README b/contrib/README new file mode 100644 index 0000000..ce8a2e4 --- /dev/null +++ b/contrib/README @@ -0,0 +1,10 @@ +The following directories contain programs of uncertain lineage where +the original authors gave no explicit instructions as to the terms of +use or redistribution. + +Based on history and e-mail exchanges I believe that "BSD" style +licensing terms are probably what was intended, but could be wrong. + + supdup/ (Unix C version of ITS SUPDUP) + read20/ (Unix utility to read TOPS-20 DUMPER tape images) + diff --git a/contrib/read20/Makefile b/contrib/read20/Makefile new file mode 100644 index 0000000..55a4d7f --- /dev/null +++ b/contrib/read20/Makefile @@ -0,0 +1,23 @@ +# Quick and dirty makefile for read20. +# Invoke with appropriate system, e.g. "make freebsd" + +SRCS= dump.h read20.c +OBJS= read20.o + +usage: + @echo 'Use appropriate system as target, eg "make freebsd"' + +freebsd: + cc -g -O -o read20 read20.c -lcompat + +osfaxp: + cc -g -O -std1 -o read20 read20.c + +linux: + cc -g -O -o read20 read20.c + +solaris: + gcc -g -O -o read20 read20.c + +solaris-cc: + /opt/SUNWspro/bin/cc -g -O -o read20 read20.c diff --git a/contrib/read20/dump.h b/contrib/read20/dump.h new file mode 100644 index 0000000..4ab04c2 --- /dev/null +++ b/contrib/read20/dump.h @@ -0,0 +1,489 @@ +/* Note: the source for DUMPER.MAC changed considerably between v.419, which + implemented formats 3,4,5, and v.563 which implemented 4,5,6. + What follows is a synthesis of info gleaned from both. +*/ + +/* COMMENT + + F O R M A T O F D U M P E R T A P E S + =========================================== + + +EACH PHYSICAL RECORD WRITTEN BY DUMPER CONTAINS ONE OR MORE +LOGICAL RECORDS, EACH OF WHICH IS 518 (1006 OCTAL) WORDS LONG. + +EACH LOGICAL RECORD HAS THE FOLLOWING FORMAT: + + !=======================================================! +CHKSUM ! CHECKSUM OF ENTIRE 518-WORD RECORD ! +0 + !-------------------------------------------------------! +ACCESS ! PAGE ACCESS BITS (CURRENTLY NOT USED) ! +1 + !-------------------------------------------------------! +TAPNO !SCD! SAVESET NUMBER ! TAPE NUMBER ! +2 + !-------------------------------------------------------! +PAGNO !F1!F2! FILE # IN SET ! PAGE # IN FILE ! +3 + !-------------------------------------------------------! +TYP ! RECORD TYPE CODE (NEGATED) ! +4 + !-------------------------------------------------------! +SEQ ! RECORD SEQUENCE NUMBER (INCREASES BY 1) ! +5 + !=======================================================! + ! ! + ! CONTENTS OF FILE PAGE IF DATA RECORD ! + ! OTHER TYPES HAVE OTHER INFORMATION HERE ! + ! ! + !=======================================================! + + +TYPE VALUE MEANING +---- ----- ------- +DATA 0 CONTENTS OF FILE PAGE +TPHD 1 NON-CONTINUED SAVESET HEADER +FLHD 2 FILE HEADER (CONTAINS FILESPEC, FDB) +FLTR 3 FILE TRAILER +TPTR 4 TAPE TRAILER (OCCURS ONLY AFTER LAST SAVESET) +USR 5 USER DIRECTORY INFORMATION +CTPH 6 CONTINUED SAVESET HEADER +FILL 7 NO MEANING, USED FOR PADDING + + +SCD (3 BITS) - 0=NORMAL SAVE, 1=COLLECTION, 2=ARCHIVE, 3=MIGRATION + +F1 F2 MEANING +-- -- ------- + 0 0 OLD-FORMAT TAPE (NO FILE # IN PAGNO BITS 2-17) + 1 1 OLD-FORMAT TAPE, CONTINUED FILE + 0 1 NEW-FORMAT TAPE (FILE # IN PAGNO BITS 2-17) + 1 0 NEW-FORMAT TAPE, CONTINUED FILE + +A DUMPER TAPE IS A COLLECTION OF RECORDS ORGANIZED IN THE +FOLLOWING FASHION: + + +!=======================================================! +! HEADER FOR FIRST SAVESET (TPHD) ! +!-------------------------------------------------------! +! USER INFO (USR) OR FILE (SEE BELOW) ! +!-------------------------------------------------------! +! USER INFO OR FILE ! +!-------------------------------------------------------! +! . ! +! . ! +! . ! +!=======================================================! +! HEADER FOR SECOND SAVESET (TPHD) ! +!-------------------------------------------------------! +! USER INFO (USR) OR FILE (SEE BELOW) ! +!-------------------------------------------------------! +! USER INFO OR FILE ! +!-------------------------------------------------------! +! . ! +! . ! +! . ! +!=======================================================! +! ! +! SUBSEQUENT SAVESETS ! +! ! +!=======================================================! +! ! +! LAST SAVESET ! +! ! +!=======================================================! +! TAPE TRAILER (TPTR) ! +!=======================================================! + + +NOTES: + +1. ON LABELED TAPES, THE TPTR RECORD APPEARS ONLY IF + THE SAVESET IS CONTINUED ON ANOTHER TAPE. + +2. SOLITARY TAPE MARKS (EOF'S) ARE IGNORED ON INPUT. + TWO CONSECUTIVE TAPE MARKS ARE INTERPRETED AS TPTR. + +3. ON LABELED TAPES, EACH SAVESET OCCUPIES EXACTLY ONE FILE. + +4. THE FIRST RECORD OF A CONTINUED SAVESET IS CTPH + INSTEAD OF TPHD. + +A DISK FILE SAVED ON A DUMPER TAPE ALWAYS HAS THIS +SEQUENCE OF RECORDS: + +!=======================================================! +! FILE HEADER (FLHD) ! +!-------------------------------------------------------! +! DATA RECORD: 1 PAGE OF FILE (DATA) ! +!-------------------------------------------------------! +! DATA RECORD: 1 PAGE OF FILE (DATA) ! +!-------------------------------------------------------! +! . ! +! . ! +! . ! +!-------------------------------------------------------! +! FILE TRAILER (FLTR) ! +!=======================================================! + +END COMMENT +*/ + +/* Additional notes from DUMPER version 563: + + CURFMT==6 ;CURRENT FORMAT NUMBER, DO NOT CHANGE + ;6 GAINED "TONEXT" RECORD TYPE + ;5 GAINED PASSWORD ENCRYPTION AND OTHER CRDIR%oids + ;4 IS THE LOWEST LEGAL TAPE TYPE + + Old DUMPERs used record offset 1 (now .FLAG) for a "page access" +word. In all cases it was set to a canned value on write and ignored +on read. This not being very useful, the word has been usurped for a +flag word in tape version 6. However, the bit values of H.HIST must +never be used as flags, since old DUMPERs always set them. + + Record type 7 WHEN WRITTEN ON TAPE is always a Filler record and +implies that the rest of the physical record can be discarded. GETREC +does not pass these records back. If GETREC does return record type 7, +it is the SAVEEN (end of saveset) record. Be careful of the +difference. SAVEEN records are generated by reading into an EOF. + + Current record header format: +.CHKSM checksum of entire record. Ignore if FL.NCK is set in .FLAG +.FLAG flags (FL.???). FL.HIS is always set for historical reasons. +.TAPNO B2 + B17+ +.PAGNO B1 + B17 + +.TYP negated record type +.SEQ sequence number (usually increases by one) + +STYP = 0 Normal Save, 1 Collection, 2 Archival, 3 Migration +OLDFLG = 1B0 on an old style tape in a TAPEEN (4) record if it isn't *really* + the end of the file, but in fact means to go to the next tape. + + The Saveset number is only filled in in +Archival/Collection/Migration savesets. + + If, on reading a tape, a sequence number does not increase, but +stays the same or goes down (on tapes with more than one logical +record per physical record), an error was encountered while writing +the tape that didn't show up while reading it. The second physical +record is ignored. + + + Tape format + + Tapes are a group of Savesets, ended by a end-of-tape record +(either TONEXT, indicating the data continued on another tape, or +TAPEEN, meaning end of all data). + + They are written as + saveset sequence + EOF (on some types of tapes) + saveset sequence + EOF (on some types of tapes) + ... + TAPEEN or TONEXT + EOF + EOF (logical EOT) + + Where a saveset sequence consists of + Saveset header (SAVEST) + File header (FILEST) | for each + File data (DATA) |for each page of data | file in the + File trailer (FILEEN) | saveset. + + A TONEXT record can occur at ANY point, indicating the next tape +is needed to read the next record. The next tape will start with a +CONTST record (continued saveset). + + And also: old tapes will have a FILEST record after a CONTST +record if mid-file, which should be ignored; and FILEEN tapes with +PG.CON set in .PAGNO are treated as TONEXT records (and are handled +that way by GETREC). + + Any physical record on tape is made up of 1-15. logical records +(always the same number of records per physical record for any given +tape). SAVEST, CONTST and TAPEEN records are always the first in +their physical records (previous physical records being padded with +FILLER records if needed to accomplish this). + + +*/ + +/* DUMPER formats */ +#define DFMTV0 0 /* BBN TENEX DUMPER format */ + /* 1 */ + /* 2 */ +#define DFMTV3 3 /* T20 V2 - FDB changes, structures, etc. */ +#define DFMTV4 4 /* T20 V3 - new GTDIR blocks */ +#define DFMTV5 5 /* T20 V6 - bigger GTDIR blocks, pwd encryption */ +#define DFMTV6 6 /* T20 V7 - record type 8, randomness */ + + +/* +EACH PHYSICAL RECORD WRITTEN BY DUMPER CONTAINS ONE OR MORE +LOGICAL RECORDS, EACH OF WHICH IS 518 (1006 OCTAL) WORDS LONG. + +(Note: max blocking factor is 15., i.e. no more than 15 logical records +per physical record.) +*/ + +/* Header of every DUMPER logical record */ +#define RECHDR_CKSUM 0 /* Checksum */ +#define RECHDR_FLAG 1 /* DV6: flags, previously ACCESS */ +#define RECHDR_TAPNO 2 /* Tape number */ +#define RECHDR_PAGNO 3 /* Page number */ +#define RECHDR_TYP 4 /* Record type (RECTYP_xxx), negated */ +#define RECHDR_SEQ 5 /* Record sequence # */ +#define RECHDR_LEN 6 /* Header size (# words) */ + +/* Fields in FLAG: + FL.HIS==(170000);Always set in .FLAG (historical, old page access bits) + FL.NCK==1B0 ; ([563],V6) No real checksum in .CHKSM +*/ +/* Fields in TAPNO: + 700000,,0 ; high 3 bits are saveset type: + ; 0 normal, 1 Collection, 2 Archival, 3 Migration + 77777,,0 ; Saveset number + 0,,777777 ; Tape number +*/ +/* Fields in PAGNO: + 400000,,0 ; PGNCFL - continued tape file + ; (set in 3(FLTR), 4(TPTR), 2(FLHD)) + ; [563] PG.CON means TONEXT + 200000,,0 ; PGNNFL - File # is valid, if complement of PGNCFL + ; [563] PG.NFN always set, even if PG.CON set too. + 177777,,0 ; File number (in saveset) + 0,,777777 ; Page number in file + +F1 F2 MEANING +-- -- ------- + 0 0 OLD-FORMAT TAPE (NO FILE # IN PAGNO BITS 2-17) + 1 1 OLD-FORMAT TAPE, CONTINUED FILE + 0 1 NEW-FORMAT TAPE (FILE # IN PAGNO BITS 2-17) + 1 0 NEW-FORMAT TAPE, CONTINUED FILE +*/ + +/* Record types (values negated in header) */ + /* [419] [563] */ +#define RECTYP_DATA 0 /* DATA DATA data record, file contents */ +#define RECTYP_TPHD 1 /* TPHD SAVEST Tape/saveset header */ +#define RECTYP_FLHD 2 /* FLHD FILEST File header */ +#define RECTYP_FLTR 3 /* FLTR FILEEN File trailer/end */ +#define RECTYP_TPTR 4 /* TPTR TAPEEN Tape trailer, saveset end */ +#define RECTYP_USR 5 /* USR DIRECT User directory info */ +#define RECTYP_CTPH 6 /* CTPH CONTST Continued saveset header */ +#define RECTYP_FILL 7 /* FILL FILL,SAVEEN Filler record */ +#define RECTYP_FLCT 8 /* TONEXT To next tape rec */ + /* (continued file) */ + +/* Record data formats (512 words following header) */ + +/* Type 0 (DATA) - File data page, all 512 words */ + +/* Types 1 and 6 (TPHD, CTPH) - Tape/saveset headers */ +/* + 0: ; FMT - A DFMTVn value + 1: ; PNT - either 3 or 20 + 2: ; TAD + + In V4,V5 the saveset name starts at 3. + In V6 there is more data: + 3: ; VOL (not used on read) + 4: ; EDT + 20: start of saveset name ; MSG +*/ + +/* Type 2 (FLHD) - File header */ +/* + 0: + 200: +*/ + +/* Type 3 (FLTR) - File trailer */ +/* + 0: - modified to reflect file dumped + +;[554] For ARCHIVed files, a tape written by 4.1 DUMPER will have +;[554] 30 FDB words, 10 words for author name, 10 words for last +;[554] writer, then 7 words of archive information. A tape written +;[554] by 6.0 DUMPER has 37 words of FDB, then the author, last writer, +;[554] and archive information. So, check the tape format so we account +;[554] for the correct number of words from FDB-start when looking for +;[554] the archive information. + + Note: the 37-word FDB appears to have its own length (in wds) as + the first word. +*/ + +/* Type 4 (TPTR) - Tape trailer */ +/* + Data portion unused +*/ + +/* Type 5 (USR) - User directory info */ +/* + May be only a user name, or full directory info if dumped under + right conditions (wheel, etc). + + 0: ; V6 fixes all ptrs to offsets before writing; + ; V4/V5 only fix for PSW and ACT. + 40: ; UHNAM + 60: ; UHPSW + 100: ; UHACT + 200: ; CDUG (0200 words) + 400: ; CDDG (0200 words) + 600: ; CDSG (0200 words) + +*/ + +/* Type 7 (FILL) - Filler record (to fill out physical record) */ +/* + Data portion unused +*/ + +/* Type 8 (FLCT) - TONEXT, file continuation (new in V6) + Note: this value was used internally in DUMPER 419 as a made-up + type called SSND (saveset end), returned when physical EOFs + were encountered. DUMPER 563 re-used 7 (FILL) internally for that + purpose. +*/ +/* + Data portion apparently unused +*/ + + /* 5 bytes per 36-bit word */ + /* 518 word logical blocks */ +#define TAPEBLK 518*5 /* Size of one logical block */ + + /* Checksum is first word */ +#define WdoffChecksum 0 +#define BtoffChecksum 0 +#define BtlenChecksum 36 + /* Page access bits is second word */ +#define WdoffAccess 1 +#define BtoffAccess 0 +#define BtlenAccess 36 + /* SCD, first 3 bits in next word */ +#define WdoffSCD 2 +#define BtoffSCD 0 +#define BtlenSCD 3 + /* Number of saveset on tape */ +#define WdoffSaveSetNum 2 +#define BtoffSaveSetNum 3 +#define BtlenSaveSetNum 15 + /* Tape number of dump */ +#define WdoffTapeNum 2 +#define BtoffTapeNum 18 +#define BtlenTapeNum 18 + /* F1, F2 Flag bits */ +#define WdoffF1F2 3 +#define BtoffF1F2 0 +#define BtlenF1F2 2 + /* File Number in Set (new format only) */ +#define WdoffFileNum 3 +#define BtoffFileNum 2 +#define BtlenFileNum 16 + /* Page Number in file */ +#define WdoffPageNum 3 +#define BtoffPageNum 18 +#define BtlenPageNum 18 + /* Record type (2's complement) */ +#define WdoffRectype 4 +#define BtoffRectype 0 +#define BtlenRectype 36 + /* Record sequence number */ +#define WdoffRecseq 5 +#define BtoffRecseq 0 +#define BtlenRecseq 36 + +#define RecHdrlen 6 /* # words in logical record header */ + + /* SCD Values */ +#define SCDNormal 0 +#define SCDCollection 1 +#define SCDArchive 2 +#define SCDMigration 3 + + /* F1, F2 Values */ +#define F1F2Old 0 +#define F1F2OldContinue 3 +#define F1F2New 1 +#define F1F2NewContinue 2 + + /* Record type values */ +#define RectypeData 0 +#define RectypeTphd 1 +#define RectypeFlhd 2 +#define RectypeFltr 3 +#define RectypeTptr 4 +#define RectypeUsr 5 +#define RectypeCtph 6 +#define RectypeFill 7 +#define RectypeTonext 8 /* V6: "to next tape" */ + +char *rectypes[] = { + "DATA", + "ISSH", + "FLHD", + "FLTR", + "TPTR", + "UDIR", + "CSSH", + "FILL", + "NEXT" +}; + +#define BtoffWord 0 +#define BtlenWord 36 + +/* Word offsets for saveset header data (Record types 1, 6) */ +#define WdoffSSFormat RecHdrlen+0 /* Saveset format (DUMPER fmt) */ +#define WdoffSSNamoff RecHdrlen+1 /* Saveset name offset */ +#define WdoffSSDate RecHdrlen+2 /* Saveset date (TAD) */ + +#define WdoffFLName 6 /* Filename offset (type 2) */ +#define WdoffFDB 134 /* FDB offset (type 2) */ + +#define WdoffFDB_CTL 01+WdoffFDB /* Control word .FBCTL */ + +#define BtoffFDB_Arc 11 /* archived */ +#define BtlenFDB_Arc 1 + +#define BtoffFDB_Inv 12 /* invisible */ +#define BtlenFDB_Inv 1 + +#define BtoffFDB_Off 13 /* offline */ +#define BtlenFDB_Off 1 + +#define WdoffFDB_PRT 04+WdoffFDB /* protection */ +#define BtoffFDB_PRT 18 +#define BtlenFDB_PRT 18 + +#define WdoffFDB_BSZ 011+WdoffFDB /* Number of bits per byte */ +#define BtoffFDB_BSZ 6 +#define BtlenFDB_BSZ 6 + +#define WdoffFDB_PGC 011+WdoffFDB /* Number of pages in the file */ +#define BtoffFDB_PGC 18 +#define BtlenFDB_PGC 18 + +#define WdoffFDB_Size 012+WdoffFDB /* Number of bytes in the file */ + +#define BtoffFDB_Size 0 +#define BtlenFDB_Size 36 + +#define WdoffFDB_Wrt 014+WdoffFDB /* Date of last write to file */ + +#define WdoffFDB_Ref 015+WdoffFDB /* read time */ + +#define WdoffFDB_PGC_A 022+WdoffFDB /* Pagecount before archive */ + +#define WdoffFDB_TP1 033+WdoffFDB /* Tape ID for archive run 1 */ + +#define WdoffFDB_SS1 034+WdoffFDB /* Saveset # for archive run 1 */ +#define BtoffFDB_SS 0 +#define BtlenFDB_SS 18 +#define WdoffFDB_TF1 034+WdoffFDB /* Tape file # for archive run 1 */ +#define BtoffFDB_TF 18 +#define BtlenFDB_TF 18 + +#define WdoffFDB_TP2 035+WdoffFDB /* Tape ID for archive run 2 */ +#define WdoffFDB_SS2 036+WdoffFDB /* Saveset # for archive run 2 */ +#define WdoffFDB_TF2 036+WdoffFDB /* Tape file # for archive run 2 */ diff --git a/contrib/read20/read20.c b/contrib/read20/read20.c new file mode 100644 index 0000000..d4696af --- /dev/null +++ b/contrib/read20/read20.c @@ -0,0 +1,1536 @@ +/* + * Program to read Tops-20 Dumper format tapes + * + * Jim Guyton, Rand Corporation + * Original 10/20/82 + * jdg: -n added 6/11/83 + * jdg: can now extract 8-bit-byte files 2/9/86 + * + * Lot of mods by Jay Lepreau, Univ of Utah, 1-2/87. + * More mods by Ken Harrenstien, 1992-98. + */ +/* KLH To-do: + Figure out some convention for file numbering like ss.nnn which + also accomodates designating savesets by sequential numbering from + start of dump (rather than using the saveset # in block header, which + is always 0 most of the time) + + Perhaps add an interactive browse capability similar to KRSTOR. + Perhaps use a semi-permanent directory generated by initial scan. +*/ +#ifdef __STDC__ /* Some compilers can't even define this correctly! */ +# define READ20_STDC __STDC__ +#else +# define READ20_STDC 0 +#endif + +#include +#include +#include +#include /* For ctime */ +#include /* For malloc */ +#include /* For strchr, strstr, memcpy, etc */ +#include +#include +#include +#if READ20_STDC +# include /* For punt() */ +#endif + +#include "dump.h" + +#define LOGFILE "Logfile" /* logfile should be changeable */ + +char *unixname(); +long getfield(); +time_t unixtime(); +#if READ20_STDC + void punt(int, char *, ...); +#else + void punt(); +#endif + +int fdTape; /* File handle for Dumper-20 format tape */ +int tbrecsiz; /* Tape buffer record size */ +int tblen; /* Tape buffer size (max recsize) */ +char *tbuffer; /* Tape buffer location */ + +long nblktape = 0; /* # blocks read on entire tape so far */ +long nblkfile = 0; /* # blocks read in current tape file */ +long nblksset = 0; /* # blocks read in current saveset */ + +char *prevblock = 0; +int firstblock = 0; /* We are reading first block of a file */ + +FILE *fpFile; /* Output file handle on extracts */ +int debug = 0; +int default_bytesize = 36; /* Default byte size for binary files */ +int wordflg = 0; /* Set 1 to force 36-bit size for all files */ +int numflg = 0; /* Non-zero if using numeric filenames */ +int keepcr = 0; /* Keep CR's in CRLF pairs in text files */ +int dodir = 0; /* directory listing */ +int xflg = 0; /* extract */ +int verbose = 0; +int fdbflg = 0; /* Show FDB contents for files listed/extracted*/ +int genflg; /* keep generation number */ +int nselect; /* number of files still to be selected by number */ +int doallflag; /* act on all files cause no args given */ +int qicflg = 0; /* Non-zero if hacking QIC tape */ +long tlocseek = 0; /* Hack: tapeloc to seek to (-s) */ +int showtloc = 0; /* Non-zero to show tapelocs on listing */ + +int number; /* Current output file "number" */ + +#define TAPE "/dev/rmt8" /* Default input tape */ + +enum { OC_ASCII, OC_8BIT, OC_WORD, OC_PAGE } + outmode; /* File output conversion mode */ +int outnfbpw; /* # of file bytes per word (0 if bytesize 0) */ +int outnfw; /* # of file words remaining (set from fdb) */ +int outnbpiw; /* # output bytes per input 36-bit file word */ +int outnbleft; /* # of output bytes left to go */ + +int bytesize; /* FDB: Number of bits/byte in current file */ +long numbytes; /* FDB: Number of bytes in current file */ +int pgcount; /* FDB: Number of twenex pages in file */ + +long tapefmt; /* DUMPER tape format from saveset header */ +long tapeno, ssno; /* Tape # and Saveset # from saveset header */ +long pageno, filenum; + +unsigned tprot; /* Tops-20 protection */ + +time_t timep[2]; +#define atime (timep[0]) +#define mtime (timep[1]) + +int offline, archived, invisible; +int apgcount, tp1, tp2, ss1, ss2, tf1, tf2; + +#define DUMPFNAMLEN (0200*5) /* Max length of dumped filename */ +char topsname[DUMPFNAMLEN]; +char sunixname[300]; + +struct want { + unsigned short ssnum; + unsigned short fnum; +} want[10000]; /* limited by 20000 char arglist */ + +int cursswant; +int compwant(); + +#define CONTAINS_BOF 1 /* Block contains the beginning of a file */ +#define CONTAINS_EOF 2 /* Block contains the end of a file */ +#define NUL_AT_END 4 /* Put a null at the end */ +#define STRING (CONTAINS_BOF|CONTAINS_EOF|NUL_AT_END) /* Make strings easy */ + +char **patterns = 0; /* Filename match patterns */ +int numpats = 0; /* Number of patterns */ +char *expression = 0; +char *re_comp_error; /* Error message from re_comp() */ +extern char *re_comp(); + +void scan(); + +char helpstr[] = "\ +Usage: read20 [switches] [patterns]\n\ + Switches must be separated.\n\ + Patterns are simple substrings of the filenames to select.\n\ + -f Specify tapefile. '-' uses stdin. Default is /dev/rmt8\n\ + -x Extract files\n\ + -t List contents (one of -t or -x must be given)\n\ + -tl Show tape locations in listing\n\ + -S Only process saveset \n\ + -e Only process filenames matching (one -e only)\n\ + -F ... Only process files numbered ...\n\ + -V Show FDB info for files extracted or listed\n\ + -s Start reading at this byte loc in tapefile (seeks)\n\ + -q Say using QIC (1/4\") cartridge tape\n\ + -v Verbose feedback\n\ + -g Keep generation # in extracted filename\n\ + -n Use numeric filenames for extracts, starting with \n\ + -W Treat all files as 36-bit. Otherwise, 7-bit files\n\ + are treated as ascii, 8-bit as 8-bit binary, and\n\ + all others as 36-bit (direct copy of tape data).\n\ + -T Treat 0 or 36-bit files as 7-bit ascii\n\ + -B Treat 0 or 36-bit files as 8-bit binary\n\ + -c Keep CRs in CRLF pairs for ascii files\n\ + -d Debug level (>0,>5,>10,>99) (default 0)\n\ +"; + +main(argc, argv) +int argc; +char *argv[]; +{ + char *tape = TAPE; /* Pathname for tape device/file */ + + /* Do switch parsing */ + + signal(SIGINT, exit); /* Allow ^C to cause profiling to finish */ + + while(argc>1 && argv[1][0] == '-'){ + switch(argv[1][1]){ + case 's': /* Seek to byte (temporary hack) */ + if (argc <= 2) + punt(0, "Need byteloc after -s\n%s", helpstr); + tlocseek = atoi(argv[2]); + argc--; argv++; + break; + case 'f': + if (argc <= 2) + punt(0, "Need filename after -f\n%s", helpstr); + tape = argv[2]; + argc--; argv++; + break; + case 'W': /* Force all files to 36-bit word bytes */ + wordflg = 1; + break; + case 'T': /* Force 0/36-bit files to 7-bit ascii */ + default_bytesize = 7; + break; + case 'B': /* Force 0/36-bit files to 8-bit bin */ + default_bytesize = 8; + break; + case 't': /* directory listing */ + if (argv[1][2] == 'l') + showtloc = 1; + else + dodir = 1; + break; + case 'x': /* extract */ + xflg = 1; + break; + case 'q': /* Using QIC (1/4") tape */ + qicflg = 1; + break; + case 'v': /* verbosity */ + verbose++; + break; + case 'V': /* Output FDB info */ + fdbflg++; + break; + case 'g': /* keep gen number */ + genflg++; + break; + case 'd': + debug = atoi(&argv[1][2]); + fprintf(stderr, "Debug value set to %d\n", debug); + break; + case 'n': /* numeric output filenames */ + if (argc <= 2) + punt(0, "Need number after -n\n%s", helpstr); + number = atoi(argv[2]); /* First file name */ + numflg = 1; + argc--; argv++; + break; + case 'c': /* keep CR`s in CR/LF pairs */ + keepcr++; + break; + case 'e': /* regular expression */ + if (argc <= 2) + punt(0, "Need expression after -e\n%s", helpstr); + if (expression) + punt(0, "Only one -e regexp allowed"); + expression = argv[2]; + if ((re_comp_error = re_comp(expression)) != 0) + punt(0, "error in -e from re_comp: %s", + re_comp_error); + argc--; argv++; + break; + case 'S': /* selected save set number */ + if (argc <= 2) + punt(0, "Need save set number after -S\n%s", helpstr); + cursswant = atoi(argv[2]); + argc--; argv++; + break; + case 'F': /* selected file numbers */ + if (argc <= 2) + punt(0, "Need file number(s) after -F\n%s", helpstr); + for (argc -= 2, argv += 2; + argc && isdigit(**argv); + argc--, argv++, nselect++) { + want[nselect].ssnum = cursswant; + want[nselect].fnum = atoi(*argv); + } + argc += 2; argv -= 2; + break; + default: + punt(0, "unknown flag %s\n%s", argv[1], helpstr); + } + argc--; argv++; + } + + if (!xflg && !dodir) + punt(0, "Need either '-x' or '-t' option.\n%s", helpstr); + + if (argc > 1) { + patterns = &argv[1]; + numpats = argc - 1; + } + doallflag = !(patterns || expression || nselect); + if (nselect) + qsort((char *)want, nselect, sizeof (struct want), compwant); + + if (!strcmp(tape, "-")) /* stdin */ + fdTape = 0; + else + fdTape = open(tape, 0); /* Open tape for read */ + if (fdTape == -1) + punt(1, "Can't open 'tape' file %s", tape); + if (tlocseek) { + if (lseek(fdTape, tlocseek, 0) == -1) + punt(1, "Can't seek to %ld on 'tape' file %s", + tlocseek, tape); + } + + tbrecsiz = TAPEBLK * 15; /* Default - use max block factor */ + tblen = ((tbrecsiz+511)/512)*512; /* Round up to modulo-512 */ + if (!(tbuffer = malloc(tblen))) + punt(1, "Can't allocate %d bytes for tape buffer", tblen); + + scan(); /* Now scan tape */ +} + +void +scan() +{ + char *tapeblock; + int rc; + int rtype; + long tloc = 0; + + rc = 0; + for ( ; ; ) /* Loop till end of tape */ + { + /*** Read a block ***/ + if (rc == 0) { + rc = getrec(fdTape, tbuffer, (qicflg ? tblen : tbrecsiz)); + if (rc > 0) + tloc += rc; + + if (qicflg && rc > 0) { + if (rc == tblen) rc = tbrecsiz; + else punt(1, "Ugh, QIC rec %d long, shd be %d", + rc, tblen); + } + if (debug > 99) + printf("rc=%d\n", rc); + if ((rc % (518*5)) != 0) { + if (rc != 0) + punt(1, "Oops. Read block len = %d", rc); + } + if (rc == 0) { + if (verbose) + printf("\nEnd of tape.\n"); + exit(0); /* Normal exit */ + } + tapeblock = tbuffer; + rc = rc - 518*5; + } + else { + tapeblock = tapeblock + 518*5; + rc = rc - 518*5; + } + + prevblock = 0; + /*** Do something with it ***/ + switch(rtype = -getfield(tapeblock, + WdoffRectype, BtoffRectype, BtlenRectype)) + { + case RectypeData: /* Data block */ + doDatablock(tapeblock); + break; + + case RectypeTphd: /* Saveset header */ + nblksset = 0; /* Start of saveset */ + doSaveset(tapeblock, 0); + break; + + case RectypeFlhd: /* File header */ + doFileHeader(tapeblock); + break; + + case RectypeFltr: /* File trailer */ + doFileTrailer(tapeblock); + break; + + case RectypeTptr: /* Tape trailer */ + doTapeTrailer(tapeblock); + break; + + case RectypeUsr: /* User directory info ? */ + if (verbose /* >= 3 */) + fprintf(stderr, "Directory block skipped\n"); + break; + + case RectypeCtph: /* Continued saveset hdr */ + nblksset = 0; /* Start of saveset */ + doSaveset(tapeblock, 1); + break; + + case RectypeFill: /* Fill block */ + if (verbose /* >= 3 */) + fprintf(stderr, "Fill block skipped\n"); + break; + + case RectypeTonext: /* FMTV6 - to next tape */ + doTonext(tapeblock); + break; + + default: + fprintf(stderr, "Unknown block type 0x%x, tapeloc %ld.\n", + rtype, tloc - rc); + if (debug == 0) /* Unless debugging, */ + punt(0, "Aborting."); /* stop now */ + break; + } + /* Done with record, bump counts */ + nblktape++; + nblkfile++; + nblksset++; + } +} + +int masks[32] = /* bitmasks for different length fields */ +{ 0x00000001, 0x00000003, 0x00000007, + 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, + 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, + 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, + 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, + 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, + 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, + 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, + 0xffffffff +}; + +long +getfield(block, wordoff, bitoff, bitlen) +char *block; /* Tape block */ +int wordoff; /* 36-bit word offset */ +register int bitoff; /* Bit offset of field (from msb) */ +register int bitlen; /* Bit length of field */ +{ + register char *p; /* Used to point into block */ + register long w32; /* First 32 bits of the 36 bit word */ + int w4; /* Last 4 bits of the 36 bit word */ + long w = 0; /* the word to return */ + + /* First, the "illegal" kludge */ + if (bitoff == 0 && bitlen == 36) { + bitoff = 4; + bitlen = 32; + } + if (bitlen > 32) + punt(0, "Can't get that large a field = %d!", bitlen); + + /* A PDP-10 (or 20) 36-bit word is laid out with the first 32 bits + as the first 4 bytes and the last 4 bits are the low order 4 bits + of the 5th byte. The high 4 bits of that byte should be zero */ + + p = block + (5*wordoff); /* Get ptr to word of interest */ + w32 = *p++ & 0377; /* First byte */ + w32 = (w32 << 8) | (*p++ & 0377); /* 2nd */ + w32 = (w32 << 8) | (*p++ & 0377); /* 3rd */ + w32 = (w32 << 8) | (*p++ & 0377); /* 4th */ + w4 = *p; /* 5th */ + if (w4 > 017) + punt(0, "Not a PDP-10 tape! w4 = octal %o", w4); + + /* Get the field right justified in the word "w". + There are three cases that I have to handle: + [1] field is contained in w32 + [2] field crosses w32 and w4 + [3] field is contained in w4 + */ + + if (bitoff+bitlen <= 32) /* [1] field is contained in w32 */ + { + w = w32 >> (32 - (bitoff+bitlen)); + } + else if (bitoff <= 32) /* [2] field crosses boundary */ + { + w = (w32 << (bitoff+bitlen-32)) + | (w4 >> (36 - (bitoff+bitlen))); + } + else /* [3] field is contained in w4 */ + { + w = w4 >> (36 - (bitoff+bitlen)); + } + w = w & masks[bitlen-1]; /* Trim to proper size */ + return(w); +} + +/* FDB extraction stuff +** by KLH, 1992. +*/ + +struct fdbent { + char *fe_name; /* Symbol name */ + int fe_typ; /* Value type (FBT_xxx) */ + int fe_woff; /* Word offset */ + int fe_boff; /* Bit offset (per MACRO, from hi-order bit) */ + int fe_bits; /* Bits ((0 || 36) == full word) */ + char *fe_show; /* Text to use when listing info */ + + long fe_lh; /* Extracted LH value */ + long fe_rh; /* Extracted RH value */ + long fe_val; /* Extracted value (what fits in a long) */ + char *fe_str; /* String value (if one) */ + time_t fe_tim; /* TAD converted to Unix timeval */ +}; +char festr_fname[DUMPFNAMLEN+1]; /* To hold extracted filename string */ +char *festr_attrs; /* Pointer to first fn attribute if any */ +char festr_aut[10*5+1]; /* To hold extracted author string */ +char festr_lwr[10*5+1]; /* To hold extracted last-writer string */ + +enum fdbtyp { + FBT_V8, /* Octal value */ + FBT_V10, /* Decimal value */ + FBT_H8, /* Two octal halfwords */ + FBT_H10, /* Two decimal halfwords */ + FBT_FLG, /* Boolean flag */ + FBT_TAD, /* T20 TAD value */ + FBT_TOD, /* T20 TAD value, or interval in days */ + FBT_AUT, /* Author string - at FDBend */ + FBT_LWR, /* Last-Writer string - at FDBend+010 */ + FBT_ACT, /* Account string - in filename */ + FBT_6BT /* Possible SIXBIT value */ +}; + +#define fedef(nam,typ,wo,bo,bs,tx) {nam,typ,wo,bo,bs,tx} + +#define FBLN0 030 /* DUMPER only saves this many actual FDB words */ + + /* NOTE!!!! FMTV6 DUMPER writes out 037 FDB words, so all the offsets + ** need to be changed if reading a format 6 tape... + */ + +#define FDBAUT_Woff (WdoffFDB+FBLN0) +#define FDBLWR_Woff (WdoffFDB+FBLN0+010) +#define FDBARCF (FBLN0+010+010) /* Offset in "DumperFDB" of ARCF blk */ +#define FDBARC_Woff (WdoffFDB+FDBARCF) + +/* Contents of ARCF block as stored by DUMPER */ +#define ARCF_AROFL 0 /* Useless flags to ARCF% */ +#define ARCF_ARTP1 1 /* == .FBTP1 */ +#define ARCF_ARSF1 2 /* == .FBSS1 */ +#define ARCF_ARTP2 3 /* == .FBTP2 */ +#define ARCF_ARSF2 4 /* == .FBSS2 */ +#define ARCF_ARODT 5 /* == .FBTDT */ +#define ARCF_ARPSZ 6 /* == AR%PSZ in .FBBBT */ + + +struct fdbent fdbt[] = { + fedef(".FBHDR",FBT_H8, 0, 0,36,"Header word"), + fedef("FB%LEN",FBT_V8, 0,35, 7,"Length of FDB"), + fedef(".FBCTL",FBT_H8, 1,35,36,"Status bits"), + + fedef("FB%TMP",FBT_FLG, 1, 0, 1,"File is temporary"), + fedef("FB%PRM",FBT_FLG, 1, 1, 1,"File is permanent"), + fedef("FB%NEX",FBT_FLG, 1, 2, 1,"File doesn't really exist"), + fedef("FB%DEL",FBT_FLG, 1, 3, 1,"File is deleted"), + fedef("FB%NXF",FBT_FLG, 1, 4, 1,"File is not yet closed"), + fedef("FB%LNG",FBT_FLG, 1, 5, 1,"File is longer than 512 pages"), + fedef("FB%SHT",FBT_FLG, 1, 6, 1,"DEC-reserved bit"), + fedef("FB%DIR",FBT_FLG, 1, 7, 1,"File is a directory"), + fedef("FB%NOD",FBT_FLG, 1, 8, 1,"File is not to be backed up"), + fedef("FB%BAT",FBT_FLG, 1, 9, 1,"File may have bad pages"), + fedef("FB%SDR",FBT_FLG, 1,10, 1,"Directory has subdirectories"), + fedef("FB%ARC",FBT_FLG, 1,11, 1,"File has archive status"), + fedef("FB%INV",FBT_FLG, 1,12, 1,"File is invisible"), + fedef("FB%OFF",FBT_FLG, 1,13, 1,"File is offline"), + fedef("FB%FCF",FBT_V8, 1,17, 4,"File class field"), + fedef("FB%NDL",FBT_FLG, 1,18, 1,"File is not to be deleted"), + fedef("FB%WNC",FBT_FLG, 1,19, 1,"File last write not closed"), + fedef("FB%FOR",FBT_FLG, 1,20, 1,"File has FORTRAN-style LPT chars"), + + fedef(".FBEXL",FBT_V8, 02,35,36,"Link to FDB of next file type"), + fedef(".FBADR",FBT_H8, 03,35,36,"Disk address of index block"), + fedef(".FBPRT",FBT_H8, 04,35,36,"File access bits"), + fedef(".FBCRE",FBT_TAD, 05,35,36,"Time of last write"), + fedef(".FBAUT",FBT_AUT, 06,35,36,"Author of file"), + fedef(".FBGEN",FBT_H8, 07,35,36,"Generation and directory numbers"), + fedef("FB%GEN",FBT_V10, 07,17,18,"Generation number"), + fedef("FB%DRN",FBT_V8, 07,35,18,"Internal directory number"), + fedef(".FBACT",FBT_ACT,010,35,36,"Account designator"), + fedef(".FBBYV",FBT_H8, 011,35,36,"File I/O information"), + fedef("FB%RET",FBT_V10,011, 5, 6,"Retention count"), + fedef("FB%BSZ",FBT_V10,011,11, 6,"File byte size"), + fedef("FB%MOD",FBT_V10,011,17, 4,"Data mode written in"), + fedef("FB%PGC",FBT_V10,011,35,18,"Page count of file"), + fedef(".FBSIZ",FBT_V10,012,35,36,"Number of bytes in file"), + fedef(".FBCRV",FBT_TAD,013,35,36,"Creation time of file"), + fedef(".FBWRT",FBT_TAD,014,35,36,"Time of last user write"), + fedef(".FBREF",FBT_TAD,015,35,36,"Time of last nonwrite access"), + fedef(".FBCNT",FBT_H10,016,35,36,"Count of writes,,references"), + fedef(".FBBK0",FBT_H8, 017,35,36,"Backup word 1"), + fedef(".FBBK1",FBT_H8, 020,35,36,"Backup word 2"), + fedef(".FBBK2",FBT_H8, 021,35,36,"Backup word 3"), + fedef(".FBBBT",FBT_H8, 022,35,36,"Archive status bits"), + fedef("AR%RAR",FBT_FLG,022, 1, 1,"User requested archival"), + fedef("AR%RIV",FBT_FLG,022, 2, 1,"System requested migration"), + fedef("AR%NDL",FBT_FLG,022, 3, 1,"Don't delete contents"), + fedef("AR%NAR",FBT_FLG,022, 4, 1,"Resist migration"), + fedef("AR%EXM",FBT_FLG,022, 5, 1,"File is exempt from migration"), + fedef("AR%1ST",FBT_FLG,022, 6, 1,"First archive pass in progress"), + fedef("AR%RFL",FBT_FLG,022, 7, 1,"Restoral failed"), + fedef("AR%WRN",FBT_FLG,022,10, 1,"File off-line exp date approaching"), + fedef("AR%RSN",FBT_V8, 022,17, 3,"Offline reason"), + fedef("AR%PSZ",FBT_V10,022,35,18,"Page count when file went offline"), + fedef(".FBNET",FBT_TOD,023,35,36,"On-line expiration date"), + fedef(".FBUSW",FBT_H8, 024,35,36,"User-settable word"), + fedef(".FBGNL",FBT_H8, 025,35,36,"Address of FDB of next generation"), + fedef(".FBNAM",FBT_H8, 026,35,36,"Pointer to filename block"), + fedef(".FBEXT",FBT_H8, 027,35,36,"Pointer to file type block"), +/* FDB words beyond this are not actually saved by DUMPER, which instead +** uses various hacks to store the information in the rest of the block. +*/ + fedef(".FBLWR",FBT_LWR,030,35,36,"Last writer to file"), + +#if 0 /* Note .FBFET vanishes completely -- no equiv in DumperFDB. */ + fedef(".FBTDT",FBT_TAD,031,35,36,"Date archived"), + fedef(".FBFET",FBT_TOD,032,35,36,"Offline expiration date"), + fedef(".FBTP1",FBT_6BT,033,35,36,"Tape ID for run 1"), + fedef(".FBSS1",FBT_H10,034,35,36,"Run 1 saveset number,,Tape file number"), + fedef(".FBTP2",FBT_6BT,035,35,36,"Tape ID for run 2"), + fedef(".FBSS2",FBT_H10,036,35,36,"Run 2 saveset number,,Tape file number"), +#endif + + fedef(".AROFL",FBT_H8, FDBARCF+ARCF_AROFL,35,36,"ARCF% flags"), + fedef(".ARTP1",FBT_6BT,FDBARCF+ARCF_ARTP1,35,36,"Archive tape 1 ID"), + fedef(".ARSF1",FBT_H10,FDBARCF+ARCF_ARSF1,35,36,"Archive tape 1 saveset,,fileno"), + fedef(".ARTP2",FBT_6BT,FDBARCF+ARCF_ARTP2,35,36,"Archive tape 2 ID"), + fedef(".ARSF2",FBT_H10,FDBARCF+ARCF_ARSF2,35,36,"Archive tape 2 saveset,,fileno"), + fedef(".ARODT",FBT_TAD,FDBARCF+ARCF_ARODT,35,36,"Date archived"), + fedef(".ARPSZ",FBT_V10,FDBARCF+ARCF_ARPSZ,35,36,"File page count") +}; +#define nfdbents ((sizeof fdbt)/(sizeof fdbt[0])) + + +fe_extract(blk, fe) +unsigned char *blk; +struct fdbent *fe; +{ + int woff = WdoffFDB + fe->fe_woff; + + switch (fe->fe_typ) { + case FBT_V8: /* Octal value */ + case FBT_V10: /* Decimal value */ + case FBT_FLG: /* Boolean flag */ + fe->fe_val = getfield(blk, woff, + (fe->fe_boff + 1 - fe->fe_bits), + fe->fe_bits); + break; + case FBT_H8: /* Two octal halfwords */ + case FBT_H10: /* Two decimal halfwords */ + case FBT_6BT: /* Two SIXBIT halves */ + fe->fe_lh = getfield(blk, woff, 0, 18); + fe->fe_rh = getfield(blk, woff, 18, 18); + break; + + case FBT_TOD: /* T20 TAD value, or interval in days */ + fe->fe_lh = getfield(blk, woff, 0, 18); + if (fe->fe_lh == 0) { /* If probably not a TAD, */ + fe->fe_rh = getfield(blk, woff, 18, 18); /* get RH */ + break; + } /* Else drop thru for TAD */ + case FBT_TAD: /* T20 TAD value */ + fe->fe_tim = unixtime(blk, woff); + break; + + case FBT_AUT: /* Author string - stored elsewhere in dumped block */ + fe->fe_lh = getfield(blk, woff, 0, 18); + fe->fe_rh = getfield(blk, woff, 18, 18); + getstring(blk, festr_aut, FDBAUT_Woff, + sizeof(festr_aut)-1,STRING); + fe->fe_str = festr_aut[0] ? festr_aut : NULL; + break; + case FBT_LWR: /* Last-Writer string - ditto */ + fe->fe_lh = getfield(blk, woff, 0, 18); + fe->fe_rh = getfield(blk, woff, 18, 18); + getstring(blk, festr_lwr, FDBLWR_Woff, + sizeof(festr_lwr)-1,STRING); + fe->fe_str = festr_lwr[0] ? festr_lwr : NULL; + break; + + case FBT_ACT: /* Account string - in filename */ + fe->fe_lh = getfield(blk, woff, 0, 18); + fe->fe_rh = getfield(blk, woff, 18, 18); + { + char *ecp, *cp = festr_attrs; + while (cp) { + if (ecp = strchr(cp, ';')) /* Tie off string first */ + *ecp++ = '\0'; + if (*cp++ == 'A') /* If this is acct string, */ + break; /* use it! */ + cp = ecp; /* Else try to continue */ + } + fe->fe_str = cp; + } + break; + default: + fprintf(stderr, "Internal error - Unknown FBT_ type: %d\n", + fe->fe_typ); + break; + } +} + +fe_show(f, fe) +FILE *f; +struct fdbent *fe; +{ + /* First check to see if value exists, and do nothing if zero */ + switch (fe->fe_typ) { + case FBT_V8: /* Octal value */ + case FBT_V10: /* Decimal value */ + case FBT_FLG: /* Boolean flag */ + if (!fe->fe_val) return; + break; + case FBT_H8: /* Two octal halfwords */ + case FBT_H10: /* Two decimal halfwords */ + case FBT_6BT: /* SIXBIT */ + case FBT_TOD: /* T20 TAD value, or interval in days */ + if (!fe->fe_lh && !fe->fe_rh) return; + break; + case FBT_TAD: /* T20 TAD value */ + if (!fe->fe_tim) return; + break; + case FBT_AUT: /* Author string - stored elsewhere in dumped block */ + case FBT_LWR: /* Last-Writer string - ditto */ + case FBT_ACT: /* Account string - in filename */ + if (!fe->fe_str) return; + break; + default: + fprintf(stderr, "Internal error - Unknown FBT_ type: %d\n", + fe->fe_typ); + return; + } + + /* Now start printing out the value */ + if (fe->fe_name[0] == '.') { /* Primary word def */ + fprintf(f, "%2o %s - %s: ", fe->fe_woff, fe->fe_name, fe->fe_show); + } else { /* Secondary bit field */ + fprintf(f, " %s (%oB%d) - %s: ", + fe->fe_name, masks[fe->fe_bits - 1], fe->fe_boff, fe->fe_show); + } + + /* Now print the value itself */ + switch (fe->fe_typ) { + case FBT_V8: fprintf(f, "%o", fe->fe_val); break; /* Octal */ + case FBT_V10: fprintf(f, "%d.", fe->fe_val); break; /* Decimal */ + case FBT_FLG: fprintf(f, "%s", fe->fe_val ? "Yes" : "No");/* Boolean */ + break; + + case FBT_H8: /* Two octal halfwords */ + if (fe->fe_lh) fprintf(f, "%o,,", fe->fe_lh); + fprintf(f, "%o", fe->fe_rh); + break; + + case FBT_H10: /* Two decimal halfwords */ + if (fe->fe_lh) fprintf(f, "%d.,,", fe->fe_lh); + fprintf(f, "%d.", fe->fe_rh); + break; + + case FBT_6BT: /* Two SIXBIT halves */ + if (fe->fe_lh) fprintf(f, "%o,,", fe->fe_lh); + fprintf(f, "%o ==> ", fe->fe_rh); + if (hwd6show(f, fe->fe_lh)) /* If LH doesn't end, */ + hwd6show(f, fe->fe_rh); /* show RH too */ + break; + + case FBT_TOD: /* T20 TAD value, or interval in days */ + if (!fe->fe_lh) { + fprintf(f, "%d. days", fe->fe_rh); + break; + } + /* Fall thru to TAD case */ + + case FBT_TAD: /* Output TAD as "dd-Mon-yy hh:mm:ss" */ + pftime(f, &fe->fe_tim); + break; + + case FBT_AUT: /* Author string - stored elsewhere in dumped block */ + case FBT_ACT: /* Account string - in filename */ + if (fe->fe_lh) fprintf(f, "%o,,", fe->fe_lh); + fprintf(f, "%o ", fe->fe_rh); + + case FBT_LWR: /* Last-Writer string - stored in dumped block. */ + /* Must skip showing actual FDB value because this is the first + ** FDB word not stored by DUMPER. This and following words are + ** instead filled by the strings for FBAUT, FBLWR, and FBARC. + */ + fprintf(f, "==> %s", fe->fe_str ? fe->fe_str : "?"); + break; + } + putc('\n', f); +} + +fdb_show(f, blk) +FILE *f; +unsigned char *blk; +{ + struct fdbent *fe; + int i; + + fprintf(f, "FDB for file %d.%d: %s\n\n", ssno, filenum, festr_fname); + for (fe = fdbt; fe <= &fdbt[nfdbents-1]; ++fe) { + fe_extract(blk, fe); + fe_show(f, fe); + } +} + +hwd6show(f, hwd) +FILE *f; +unsigned long hwd; /* 18-bit halfword value - 3 SIXBIT chars */ +{ + int ch; + if (ch = (hwd>>12) & 077) { + fputc(ch + 040, f); + if (ch = (hwd>>6) & 077) { + fputc(ch + 040, f); + if (ch = hwd & 077) { + fputc(ch + 040, f); + return 1; + } + } + } + return 0; +} + +pftime(f, atim) +FILE *f; +time_t *atim; +{ + char *cp = ctime(atim)+4; + fprintf(f, "%.2s-%.3s-%.2s %.8s", cp+4, cp, cp+18, cp+7); +} + +doDatablock(block) +char *block; +{ + /* max is 5 bytes per word */ + static char buf[(512*5)+1]; /* A page of characters */ + int ct, wct; + int maxperblock; + int nout, type; + + if (debug > 10) + printf("*"); + if (fpFile == NULL) + return; + + maxperblock = 512 * outnbpiw; /* # output bytes per 512-wd block */ + + if (firstblock) type = CONTAINS_BOF; + else type = 0; + + if (outnbleft > maxperblock) + ct = maxperblock, wct = 512; + else { + ct = outnbleft, wct = outnfw; + type |= CONTAINS_EOF; + } + + switch (outmode) { + case OC_ASCII: + nout = getstring(block, buf, 6, ct, type); + fwrite(buf, 1, nout, fpFile); + break; + case OC_8BIT: + getbytes(block, buf, 6, ct); + fwrite(buf, 1, ct, fpFile); + break; + case OC_WORD: /* No conversion needed */ + fwrite(block + (6*5), 1, ct, fpFile); + break; + case OC_PAGE: /* Cannot do anything for now */ + break; + } + if (ferror(fpFile)) + punt(1, "Error writing %s", sunixname); + + firstblock = 0; + outnbleft -= ct; + outnfw -= wct; +} + +/*ARGSUSED*/ +doSaveset(block, contflag) +char *block; +int contflag; +{ + int ssnoff; + long hwd; + char name[140]; /* Size must be mod 5 */ + time_t t; + + if (debug > 10) { + printf("\nSaveset header:\n"); + showblk(stdout, block, 0, 100); + } + tapeno = getfield(block, WdoffTapeNum, BtoffTapeNum, BtlenTapeNum); + ssno = getfield(block, WdoffSaveSetNum, BtoffSaveSetNum, + BtlenSaveSetNum); + + /* Find offset to saveset name. Use same algorithm as DUMPER here. + */ + hwd = getfield(block, WdoffSSFormat, 0, 18); /* Get LH of fmt */ + if (hwd & (0177L<<(18-7))) { + tapefmt = 0; /* Format wd has ASCII - old fmt! */ + ssnoff = 0; /* Starts with saveset name */ + } else { + /* Else use RH as format number (actually whole wd, but so what) */ + tapefmt = getfield(block, WdoffSSFormat, 18, 18); + ssnoff = getfield(block, WdoffSSNamoff, 18, 18); + if (ssnoff >= 512) { /* Sanity check */ + printf("Saveset header error: name offset of %ld is > 512!\n", + ssnoff); + ssnoff = 3; /* Use usual default instead */ + } + } + + getstring(block, name, RecHdrlen+ssnoff, sizeof(name), STRING); + name[sizeof(name)-1] = '\0'; /* Ensure terminated */ + + t = unixtime(block, WdoffSSDate); + if (dodir || verbose) { + if (showtloc) + printf("B%ld: ", nblktape); + printf("Tape %d: %sSaveset %d \"%s\" ", + tapeno, (contflag ? "Continued " : ""), + ssno, name); + pftime(stdout, &t); + printf("\n"); + } + +} + +static void folddown(to, from) +register char *to, *from; +{ + for ( ; *from; ++from) + *to++ = (isupper(*from) ? tolower(*from) : *from); + *to = '\0'; +} + +doFileHeader(block) +char *block; +{ + char *ts; + static char prt_ar[2] = {'-', 'A'}; + static char prt_inv[2] = {'-', 'I'}; + static char prt_off[2] = {'-', 'O'}; + + if (debug > 5) + printf("File Header block:\n"); + + filenum = getfield(block, WdoffFileNum, BtoffFileNum, BtlenFileNum); + getstring(block, festr_fname, WdoffFLName, sizeof(festr_fname), STRING); + if (festr_attrs = strchr(festr_fname, ';')) /* Chop off ;Pprot;Aacct */ + *festr_attrs++ = 0; + folddown(topsname, festr_fname); + + fpFile = NULL; + + if ( doallflag || + (patterns && patternmatch()) || + (expression && expmatch()) || + (nselect && fmatch()) ) { + getfdbinfo(block); + pageno = getfield(block, WdoffPageNum, BtoffPageNum, BtlenPageNum); + + if (dodir || verbose || fdbflg) { + if (fdbflg) { + printf("\n"); + fdb_show(stdout, block); + printf("\n"); + } + if (showtloc) + printf("B%ld: ", nblktape); + if (verbose) + printf("%3d %5d ", ssno, filenum); + printf("%c%c%c", prt_ar[archived], prt_off[offline], + prt_inv[invisible]); + printf(" %4d %8d %2d %06o ", offline ? apgcount : pgcount, + numbytes, bytesize, tprot); + pftime(stdout, &mtime); + printf(" %s", topsname); +#if 0 /* KLH: fix this later, currently vars are always zero */ + if (archived && verbose /* >= 2 */) + printf(" %x %3d %4d %x %3d %4d", tp1, ss1, tf1, tp2, ss2, tf2); +#endif + if (pageno != 0) + printf(" Split file, part 2"); + } + + if (xflg) { + /* Decide bytesize (mode) for file extraction */ + if (bytesize > 36) + bytesize = 36; + if (bytesize == 0 && numbytes) { + /* Probably a paged holey file, but if file len set, try 36 */ + bytesize = 36; /* Cross fingers */ + } + if (!bytesize) { /* If size still zero, empty file! */ + outnfbpw = 0; /* # file bytes/wd */ + outnfw = 0; /* # file words */ + } else { + outnfbpw = 36/bytesize; /* # file bytes/wd */ + outnfw = (numbytes + outnfbpw-1) / outnfbpw; /* # file wds */ + } + outnbpiw = 5; /* Default output bytes per input wd */ + + if (!bytesize) { + outmode = OC_PAGE; + outnbpiw = outnbleft = 0; + } else if (wordflg) { + outmode = OC_WORD; + outnbpiw = 5; + outnbleft = outnbpiw * outnfw; + } else switch (bytesize) { + case 7: + outmode = OC_ASCII; + outnbpiw = 5; + outnbleft = numbytes; + break; + case 8: + outmode = OC_8BIT; + outnbpiw = 4; + outnbleft = numbytes; + break; + case 36: + if (default_bytesize == 7) { + outmode = OC_ASCII; + outnbpiw = 5; + outnbleft = outnbpiw * outnfw; + break; + } else if (default_bytesize == 8) { + outmode = OC_8BIT; + outnbpiw = 4; + outnbleft = outnbpiw * outnfw; + break; + } + default: + outmode = OC_WORD; + outnbpiw = 5; + outnbleft = outnbpiw * outnfw; + break; + } + + if (outmode != OC_PAGE && !offline) { + if (pageno != 0) { /* continued file */ + long missiwds = pageno * 512; /* Missing input wds */ + long missob = missiwds * outnbpiw; /* Missing out bytes */ + + outnfw -= missiwds; + outnbleft -= missob; + if (!(dodir || verbose)) + printf("%s: Split file, part 2", topsname); + printf(": %ld file words (%ld output bytes) missing.", + missiwds, missob); + if (!(dodir || verbose)) + putchar('\n'); + } + firstblock = 1; + fpFile = fopen(unixname(topsname), "w"); + if (fpFile == NULL) + punt(1, "Can't open %s for write", sunixname); + else if (verbose) + printf(" Extracted."); + if (fchmod(fileno(fpFile), t2uprot(tprot) & ~0111) < 0) + punt(1, "fchmod on %s", sunixname); + } else if (verbose) + printf(" Skipping -- %s file.", + offline ? "offline" : "paged/holey"); + } + + if (dodir || verbose) + putchar('\n'); + } +} + +/* Return 1 if topsname matches any of the "extraction" strings. */ +patternmatch() +{ + register int i; + + for (i = 0; i < numpats; i++) + if (strstr(topsname, patterns[i])) + return (1); + return (0); +} + +/* Return 1 if topsname matches the regular expression. */ +expmatch() +{ + register int match; + + if (expression) { + if ((match = re_exec(topsname)) == -1) + punt(0, "re_exec: internal error on %s", topsname); + else + return (match); + } + return (0); +} + +int widx; + +/* Return 1 if current file number matches one selected by arg line. */ +fmatch() +{ + + while (want[widx].ssnum < ssno) + widx++; + if (want[widx].ssnum > ssno) + return 0; + while (want[widx].fnum < filenum) + widx++; + if (want[widx].fnum > filenum) + return 0; + return 1; +} + +/* + * Sets a bunch of global variables to info from the fdb. + * For some reason the archive tape info is garbage. + */ +getfdbinfo(block) +char *block; +{ + + mtime = unixtime(block, WdoffFDB_Wrt); + atime = unixtime(block, WdoffFDB_Ref); + + bytesize = getfield(block, WdoffFDB_BSZ, BtoffFDB_BSZ, BtlenFDB_BSZ); + numbytes = getfield(block, WdoffFDB_Size, BtoffFDB_Size,BtlenFDB_Size); + pgcount = getfield(block, WdoffFDB_PGC, BtoffFDB_PGC, BtlenFDB_PGC); + tprot = getfield(block, WdoffFDB_PRT, BtoffFDB_PRT, BtlenFDB_PRT); + + archived = getfield(block, WdoffFDB_CTL, BtoffFDB_Arc, BtlenFDB_Arc); + invisible= getfield(block, WdoffFDB_CTL, BtoffFDB_Inv, BtlenFDB_Inv); + offline = getfield(block, WdoffFDB_CTL, BtoffFDB_Off, BtlenFDB_Off); + apgcount = getfield(block, WdoffFDB_PGC_A, BtoffFDB_PGC, BtlenFDB_PGC); + /* The rest is bogus. */ + tp1 = getfield(block, WdoffFDB_TP1, 0, 36); + tp2 = getfield(block, WdoffFDB_TP2, 0, 36); + ss1 = getfield(block, WdoffFDB_SS1, BtoffFDB_SS, BtlenFDB_SS); + ss2 = getfield(block, WdoffFDB_SS2, BtoffFDB_SS, BtlenFDB_SS); + tf1 = getfield(block, WdoffFDB_TF1, BtoffFDB_TF, BtlenFDB_TF); + tf2 = getfield(block, WdoffFDB_TF2, BtoffFDB_TF, BtlenFDB_TF); +} + +/*ARGSUSED*/ +doFileTrailer(block) +char *block; +{ + if (debug > 10) printf(" File trailer\n"); + if (fpFile != NULL) { + if (fclose(fpFile) == EOF) + punt(1, "fclose: write error on %s", sunixname); + fpFile = NULL; + utime(sunixname, timep); + if (outnbleft || outnfw) + printf("%s: Split file, part 1: %ld file words (%ld output bytes) left\n", + topsname, outnfw, outnbleft); + } +} + +/*ARGSUSED*/ +doTonext(block) +char *block; +{ + if (dodir || verbose) { + if (showtloc) + printf("B%ld: ", nblktape); + printf("TONEXT record - continued on next tape\n"); + } +} + +/*ARGSUSED*/ +doTapeTrailer(block) +char *block; +{ + if (dodir || verbose) { + if (showtloc) + printf("B%ld: ", nblktape); + printf("Tape trailer - Saveset End\n"); + } +} + + +#if READ20_STDC + void punt(int prterrno, char *fmt, ...) +#else + void punt(prterrno, fmt, a,b,c,d,e) +int prterrno; /* TRUE to print errno string */ +char *fmt; +#endif +{ + extern int errno, sys_nerr; + + fprintf(stderr, "read20: "); +#if READ20_STDC + { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } +#else + fprintf(stderr, fmt, a,b,c,d,e); +#endif + if (prterrno) { + fprintf(stderr, ": "); + if (errno >= 0 && errno < sys_nerr) + perror(""); + else + fprintf(stderr, "ERRNO = %d\n", errno); + } + else + fprintf(stderr, "\n"); + exit(1); +} + +/* + * Unpack into buffer 's' the 7 bit string stored in 'block' and + * append a null char. Optionally strip CR's from CRLF pairs. 'max' + * is the max number of 7-bit chars to unpack from 'block', not the + * max to put into 's' (that's important!). This only works if + * getstring() is always called with 'max' mod 5 == 0, except for the + * last call on "contiguous" blocks. + * Returns number of chars stored in output buffer. + */ +int +getstring(block, s, wordoff, max, type) +register unsigned char *block; /* Tape block */ +register char *s; /* Destination string buffer */ +int wordoff; /* 36-bit offset from start of tape block */ +int max; /* Max number of characters to xfer into s */ +int type; /* Info about block we are reading (first, last + or string) */ +{ + register int ct; /* Number of characters loaded so far */ + register char *op; /* Output pointer for -> hacking */ + register int c; + char *orig = s; /* Save for debugging */ + unsigned long top4; + static int state; +#define NORMAL 1 +#define LAST_WAS_CR 2 + + op = s; + + block += wordoff * 5; + + for (ct = 0; ct < max; ct += 5) + { + /* Copy 5 7-bit bytes portably from 8-bit byte frames. + ** This depends on unsigned char being implemented correctly. + */ + *op++ = block[0] >> 1; + *op++ = ((block[0] << 6) | (block[1] >> 2)) & 0177; + *op++ = ((block[1] << 5) | (block[2] >> 3)) & 0177; + *op++ = ((block[2] << 4) | (block[3] >> 4)) & 0177; + *op++ = ((block[3] << 3) | ((block[4]&017) >> 1)) & 0177; + block += 5; + } + + if (keepcr) return (max); + + op = s; + + if (type & CONTAINS_BOF) state = NORMAL; + + for (ct = 0; ct < max; ct++) + { + c = *s++; + + switch (state) { + case NORMAL: + if (c != '\r') + *op++ = c; + else + state = LAST_WAS_CR; + + continue; + + case LAST_WAS_CR: + if (c == '\n') { + *op++ = c; + state = NORMAL; + continue; + } + if (c == '\r') { + *op++ = c; + continue; + } + *op++ = '\r'; + *op++ = c; + state = NORMAL; + } + } + + if (type & CONTAINS_EOF) { + if (state == LAST_WAS_CR) + *op++ = '\r'; + } + if (type & NUL_AT_END) *s++ = 0; + + return (op - orig); +} + +/* getbytes: like getstring, but ... + 1) uses 8 bit bytes + 2) doesn't stop on a zero +*/ +getbytes(block, s, wordoff, max) +char *block; /* Tape block */ +register char *s; /* Destination string buffer */ +int wordoff; /* 36-bit offset from start of tape block */ +int max; /* Max number of characters to xfer into s */ +{ + register int i; /* Counter for five characters per word */ + + int ct = 0; /* Number of characters loaded so far */ + char *orig = s; /* Save for debugging */ + + block += wordoff * 5; + + for (ct = 0; ct < max; ct += 4) + { + (void) memcpy(block, s, 4); + block += 5; + s += 4; + } +} + +showblk(f, block, offset, nwds) +register FILE *f; +register unsigned char *block; +{ + register int i; + register unsigned long lh, rh; + register int c; + char str[6]; + + str[5] = 0; + for (i = offset; --nwds >= 0; ++i) + { + lh = getfield(block, i, 0, 18); + rh = getfield(block, i, 18, 18); + + if (!lh && !rh) { + fprintf(f, "%4o: 0\n", i); + continue; + } + + /* Convert to word of ASCII */ + c = (lh >> (18- 7)) & 0177; + str[0] = (isprint(c) ? c : '.'); + c = (lh >> (18-14)) & 0177; + str[1] = (isprint(c) ? c : '.'); + c = ((lh & 017)<<3) | (rh>>(18-3)); + str[2] = (isprint(c) ? c : '.'); + c = (rh >> (18-10)) & 0177; + str[3] = (isprint(c) ? c : '.'); + c = (rh >> (18-17)) & 0177; + str[4] = (isprint(c) ? c : '.'); + + fprintf(f, "%4o: %6lo,,%6lo %s\n", i, lh, rh, str); + } +} + +#define DayBaseDelta 0117213 /* Unix day 0 in Tenex format */ + +/* + * This screws up on some of the atime's we see, including, yielding, e.g. + * Fri Dec 23 23:28:16 1994 + * Fri Dec 23 23:28:16 1994 + * Tue Jan 13 07:57:03 1987 + */ +time_t +unixtime(block, wordoff) +char *block; +int wordoff; +{ + long int t, s; + double d; + + t = getfield(block, wordoff, 0, 18); /* LH is day */ + if (t == 0) return(0); /* 0 means never referenced */ + + t -= DayBaseDelta; /* Switch to unix base */ + /* Now has # days since */ + /* Jan 1, 1970 */ + if (t < 0) { + fprintf(stderr, "ERROR - Date earlier than Jan 1,1970!!!\n"); + } + + s = getfield(block, wordoff, 18, 18); /* RH is fraction of day */ + + /* Note that the following calculation must be performed in the order shown + in order to preserve precision. It should also be done in double prec. + floating point to prevent overflows. + */ + d = ((double)s * (24*60*60)) /* Make it double and pre-multiply */ + / (1<<18); /* Then divide by 1<<18 to get secs */ + s = d; /* Get back into integer form */ + if ((d - s) >= 0.5) /* Find remainder -- round up? */ + ++s; /* Yup */ + + return s + (t*24*60*60); /* Add day base and return */ +} + +char * +unixname(name) +char *name; +{ + static FILE *log = NULL; + register char *t, *p; + static char lastdir[128]; + struct stat stb; + int dlen; + int mask; + register int newdir = 0; + + if (numflg) { /* If numeric filenames */ + if (log == NULL) log = fopen(LOGFILE, "a"); + fprintf(log, "%d is %s\n", number, name); + sprintf(sunixname, "%d", number++); + return(sunixname); + } + + strcpy(sunixname, strchr(name, '<') + 1); /* trim off device */ + t = strrchr(sunixname, '>'); /* find end of directory */ + *t = '.'; + dlen = t - sunixname; + + if (strncmp(lastdir, sunixname, dlen)) {/* maybe new dir */ + strncpy(lastdir, sunixname, dlen); /* remember it */ + lastdir[dlen] = '\0'; /* Ensure null terminated */ + newdir = 1; + } + for (p = sunixname; p <= t; p++) + if (*p == '.' || *p == '/') { + if (newdir) { + *p = '\0'; /* temporarily null it off */ + if (stat(sunixname, &stb) < 0) { + mask = umask(2); + if (mkdir(sunixname, 0777) < 0) + punt(1, "mkdir %s failed", sunixname); + umask(mask); + } + } + *p = '/'; + } + + for (p = t+1; *p; p++) + if (*p == '/') *p = '\\'; + + if (!genflg) { + t = strrchr(sunixname, '.'); /* find last . */ + *t = 0; /* zap it out */ + } + return(sunixname); +} + +int +t2uprot(prot) +register unsigned prot; +{ + register unsigned tprot, uprot; + register int tshift; + +#ifdef notdef + if (f->FB_dir) { /* THIS WON'T WORK! */ + punt(0, "Can't handle directory %s", topsname); + prot = gtdirprot(_dirnm(jfn)); /* returns 20 fmt protection */ + for (tshift=12, uprot=0; tshift >= 0; tshift -= 6) { + tprot = prot >> tshift; /* pick up next field */ + uprot <<= 3; + if (tprot & DP_rd) + uprot |= WREAD|WEXEC; /* world read, world execute */ + if (tprot & (DP_cn|DP_cf)) /* allow write for either conn. */ + uprot |= WWRITE; /* access or add files access */ + } + } + else +#endif + { /* do it this way so easily modified-- i know it could be faster */ + for (tshift=12, uprot=0; tshift >= 0; tshift -= 6) { + tprot = prot >> tshift; + uprot <<= 3; + uprot |= (tprot >> 3) & 07; /* just r,w,x */ + } + } + return uprot; +} + +#ifdef notdef +#define HOUR 3600 +#define DAY (HOUR*24) +#define DAY0 40587 /* number of days between tops20 0 day and Unix 0 day */ + +#define makeword(l, r) ( ((l) << 18) | (r) ) +#define getright(b) ( (b) & 0777777 ) +#define getleft(b) ( (b) >> 18 ) + +/* Convert Tops-20 to Unix time -- curently incomplete due to 32 < 36 bits */ +int +_t2utim(t) +unsigned t; +{ + register ticks, rh, secs; + + ticks = t - makeword(DAY0, 0); + rh = getright(ticks) * DAY; + secs = rh >> 18; + if (rh % makeword(1,0) > 0400000) + secs++; /* round up */ + return (getleft(ticks) * DAY) + secs; +} +#endif + +int +compwant(w1, w2) +register struct want *w1, *w2; +{ + int sdif; + + if (sdif = w1->ssnum - w2->ssnum) + return sdif; + return (w1->fnum - w2->fnum); +} + +getrec(fd, addr, len) + int len; + char *addr; +{ + register int cc, remaining = len; + + while (remaining > 0) + { + cc = read(fd, addr, remaining); + +/* fprintf(stderr, "read(0, %x, %d) = %d\n", addr, remaining, cc);*/ + + if (cc == remaining) return(len); + + if (cc == 0) return(len - remaining); + + if (cc < 0) { + fprintf(stderr, "Got an error, errno=%d\n", errno); + exit(1); + } + +/* Hack hack, cough... If we are reading from a tape (or a file), then don't + try to pad the record... + */ + if (fd != 0) return(cc); + + remaining -= cc; + addr += cc; + } + return(len); +} diff --git a/contrib/supdup/COPYING b/contrib/supdup/COPYING new file mode 100644 index 0000000..7ffb2dc --- /dev/null +++ b/contrib/supdup/COPYING @@ -0,0 +1,28 @@ +Date: Wed, 03 Oct 2001 14:17:49 -0400 +From: dab@froghouse.org +To: klh@alum.mit.edu +Message-ID: <87y9msy4du.wl@ariki.froghouse.org> + +At Wed, 3 Oct 2001 11:43:45 EDT, +Ken Harrenstien wrote: + +> Dave, any problems with redistributing this code, or some version of +> supdup, along with the KLH10 distribution? You have the original +> copyright even if it's not explicitly stated. It is probably a good +> idea to add something that clearly says what rights others have (GPL +> or whatever). I can send you the latest if you like. + +If I'd thought about it at the time I probably would have used the old +MIT copyright, the same that we put on PC/IP and the C Gateway. +From what I hear, not having actually looked into any of this, the BSD +copyright is pretty much the same thing. + +Anyway, you're certainly welcome to redistribute the code as far as +I'm concerned. + +Oh, I remember now why I didn't put a copyright on it. It was because +I used the BSD telnet sources as a starting point for the supdup +programs and the BSD code was not free at the time. Not very much +telnet code survived in the end but it is where I started from. + + -Dave diff --git a/contrib/supdup/INFO b/contrib/supdup/INFO new file mode 100644 index 0000000..f9a3706 --- /dev/null +++ b/contrib/supdup/INFO @@ -0,0 +1,32 @@ +This file contains information on know problems, bugs, and misfeatures of +supdup, as well as any other random pieces of information that need to +be somewhere. + +SUPDUPD needs a new /bin/login because the standard login trashes the +environment. The /bin/login that we use is included. The only +requirement is that the TERMCAP (and TERMINFO if you're using it) gets +passed through as well as the TERM environment variable. + +The server should do the same optimization with character insert and +delete that it does with line insert and delete. + +I probably should make use of scroll regions. But this is a pain. + +If TTYLOC is defined, then the SUPDUP location feature uses Romkey's +ttyloc code. This could easily be replaced by whatever your +particular machine does about tty location, or left out all together +of course. The user supdup doesn't yet send TTYLOC information. + +The banner should tell you to turn off overstrike if necessary. + +3600's have this bug where if you position the cursor at the beginning +of the line and do a newline, the first character of the line is erased. +I have programmed around this bug to some extent, but it sometimes +reappears. They also have a bug that if you type a meta character the +character that gets sent is shifted and if you type meta shift character +it sends a lowercase character. There is nothing I can do about this. + +For some reason talk, amoung a few other things, core dumps when +supduping in from a lisp machine (either a 3600 or a cadr). I've seen +the same bug a BBN bitgraph. It seems to be a bug with programs which +use curses and is evoked by large screen sizes. diff --git a/contrib/supdup/Makefile b/contrib/supdup/Makefile new file mode 100644 index 0000000..677beb1 --- /dev/null +++ b/contrib/supdup/Makefile @@ -0,0 +1,44 @@ +# Makefile for the supdup server and user. + +# Definitions for supdupd. +# TERMINFO Does setup for terminfo. +# TTYLOC Sets your ttyloc from supdup. The code included is specific +# to borax. You would probably want to replace the code in +# those sections with whatever you do locally for ttyloc. +# BANNER +# SBANNER +# DEBUG +# +# Definitions for supdup. +# TERMCAP Uses the termcap database. +# TERMINFO Uses the terminfo database. Exactly one of TERMCAP or +# TERMINFO must be defined and the corresponding library +# (-ltermcap or -lterminfo) must be linked in. +# DEBUG + +# This printf string is send as the supdup server's greeting. +# Its `arguments' are the local and remote host names. +# It should output ASCII +sbanner = "%s SUPDUP from %s.\r\nBugs to bug-unix-supdup@ai.mit.edu" + +# This printf string is sent before /bin/login is invoked. +# Its `argument' is the local host name. +# It should output SUPDUP codes (eg #o207 rather than #o15 #o10 for newline) +banner ="SunOS Unix (%s)\207%s" + +#Uncomment next line if your host isn't running in the ancient past +#lresolv = -lresolv +lresolv = + +all: supdup supdupd supdup-login + +supdup: supdup.c termcaps.h + cc -g -o supdup -DTERMCAP supdup.c -ltermcap ${lresolv} + +supdupd: supdupd.c supdup.h + cc -g -o supdupd supdupd.c ${lresolv} '-DBANNER=${banner}' '-DSBANNER=${sbanner}' -DMIT -DTTYLOC -DKEEPALIVE -DBSD4_3 + +#in.supdupd: supdupd + +supdup-login: supdup-login.c + cc -g -o supdup-login supdup-login.c diff --git a/contrib/supdup/sd.tc b/contrib/supdup/sd.tc new file mode 100644 index 0000000..265ef59 --- /dev/null +++ b/contrib/supdup/sd.tc @@ -0,0 +1 @@ +setenv TERMCAP 'SD|supdup|SUPDUP virtual terminal:co#132:li#52:am:vb=\177\023:nd=\177\020:MT:cl=\177\022:so=\177\031:se=\177\032:pt:ce=\177\005:ec=\177\006:cd=\175\004:bs:up=\177\041:cm=\177\021%+ %+ :do=\177\014:nl=\177\014:al=\177\025\001:dl=\177\026\001:AL=\177\025%.:DL=\177\026%.:ns:km:pc=\000' diff --git a/contrib/supdup/supdup-login.c b/contrib/supdup/supdup-login.c new file mode 100644 index 0000000..9d29988 --- /dev/null +++ b/contrib/supdup/supdup-login.c @@ -0,0 +1,676 @@ +/* Lucid changes and supdup changes merged into + vanilla quotaless sun /bin/login by Mly 9-Jul-87 16:17:01 + + supdup changes: + pass on envvar TERMCAP if TERM is "supdup" + + lucid changes (kdo): + disconnect after > 5 failed login attempts + + always prompt for password when insecure login + + if compiled with -DPARANOIA, disallows passwords + of length < 6 when insecure !!!!! This includes + null passwords. +*/ + +/* + * login [ name ] + * login -r hostname (for rlogind) + * login -h hostname (for telnetd, etc.) + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SCPYN(a, b) strncpy(a, b, sizeof(a)) + +#define NMAX sizeof(utmp.ut_name) + +#define FALSE 0 +#define TRUE -1 + +char QUOTAWARN[] = "/usr/ucb/quota"; /* warn user about quotas */ +char CANTRUN[] = "login: Can't run "; + +char nolog[] = "/etc/nologin"; +char qlog[] = ".hushlogin"; +char securetty[] = "/etc/securetty"; +char maildir[30] = "/usr/spool/mail/"; +char lastlog[] = "/usr/adm/lastlog"; +struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" }; +struct sgttyb ttyb; +struct utmp utmp; +char minusnam[16] = "-"; +/* + * This bounds the time given to login. We initialize it here + * so it can be patched on machines where it's too small. + */ +int timeout = 60; + +char homedir[64] = "HOME="; +char shell[64] = "SHELL="; +char term[64] = "TERM="; +char user[20] = "USER="; +char logname[23] = "LOGNAME="; + +/* NOTE WELL extra zero at the end of envinit + they are for possible TERMCAP */ +char *envinit[] = + { homedir, shell, + "PATH=:/usr/ucb:/bin:/usr/bin", + user, logname, + term, + /* May be filled in by TERMCAP */ + 0, + 0 }; + +#define LOG_SECURITY LOG_CRIT + +struct passwd *pwd; +struct passwd *getpwnam(); +char *strcat(), *rindex(), *index(); +int setpwent(); +int timedout(); +char *ttyname(); +char *crypt(); +char *getpass(); +char *stypeof(); +extern char **environ; +extern int errno; + +struct tchars tc = { + CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK +}; +struct ltchars ltc = { + CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT +}; + +int rflag; +char rusername[NMAX+1], lusername[NMAX+1]; +char rpassword[NMAX+1]; +char name[NMAX+1]; +char *rhost; + +main(argc, argv) + char *argv[]; +{ + register char *namep; + int t, f, c, i; + int invalid, quietlog; +/* loseit */ + int ttysecure = 0; +/* loseit */ + FILE *nlfd; + char *ttyn, *tty; + int ldisc = NTTYDISC, zero = 0; + int locl = LCRTBS|LCTLECH|LDECCTQ; + + signal(SIGALRM, timedout); + alarm(timeout); + signal(SIGQUIT, SIG_IGN); + signal(SIGINT, SIG_IGN); + setpriority(PRIO_PROCESS, 0, 0); + for (t = getdtablesize(); t > 3; t--) + close(t); + /* + * -r is used by rlogind to cause the autologin protocol; + * -h is used by other servers to pass the name of the + * remote host to login so that it may be placed in utmp and wtmp + */ + if (argc > 1) { + if (strcmp(argv[1], "-r") == 0) { + rflag = doremotelogin(argv[2]); + SCPYN(utmp.ut_host, argv[2]); + argc = 0; + } + if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { + SCPYN(utmp.ut_host, argv[2]); + argc = 0; + } + } + ioctl(0, TIOCLSET, &zero); + ioctl(0, TIOCNXCL, 0); + ioctl(0, FIONBIO, &zero); + ioctl(0, FIOASYNC, &zero); + ioctl(0, TIOCGETP, &ttyb); + /* + * If talking to an rlogin process, + * propagate the terminal type and + * baud rate across the network. + */ + if (rflag) + doremoteterm(term, &ttyb); + if (ttyb.sg_ospeed >= B1200) + locl |= LCRTERA|LCRTKIL; + ioctl(0, TIOCLSET, &locl); + ioctl(0, TIOCSLTC, <c); + ioctl(0, TIOCSETC, &tc); + ioctl(0, TIOCSETP, &ttyb); + ttyn = ttyname(0); + if (ttyn == (char *)0) + ttyn = "/dev/tty??"; + tty = rindex(ttyn, '/'); + if (tty == NULL) + tty = ttyn; + else + tty++; +/* loseit */ + t = 0; +/* loseit */ + do { + ldisc = 0; + ioctl(0, TIOCSETD, &ldisc); + invalid = FALSE; + SCPYN(utmp.ut_name, ""); + /* + * Name specified, take it. + */ + if (argc > 1) { + SCPYN(utmp.ut_name, argv[1]); + argc = 0; + } + /* + * If remote login take given name, + * otherwise prompt user for something. + */ + if (rflag) { + SCPYN(utmp.ut_name, lusername); + /* autologin failed, prompt for passwd */ + if (rflag == -1) + rflag = 0; + } else + getloginname(&utmp); + if (!strcmp(pwd->pw_shell, "/bin/csh")) { + ldisc = NTTYDISC; + ioctl(0, TIOCSETD, &ldisc); + } + /* + * If no remote login authentication and + * a password exists for this user, prompt + * for one and verify it. + */ +/* loseit */ + ttysecure = rootterm(tty); /* See if tty believed secure */ +/* loseit */ + + if (!rflag && (*pwd->pw_passwd != '\0' +/* loseit */ + /* Always prompt for password if insecure */ + || !ttysecure +/* loseit */ + )) { + char *pp; + + setpriority(PRIO_PROCESS, 0, -4); + pp = getpass("Password:"); + namep = crypt(pp, pwd->pw_passwd); + setpriority(PRIO_PROCESS, 0, 0); +/* loseit */ +#ifdef PARANOIA + /* If not secure check that password is long enough + and don't allow no-password logins */ + if (!ttysecure) { + if (strlen(pp)<6) invalid = TRUE; + if (*pwd->pw_passwd == '\0') invalid = TRUE; + } +#endif /* loseit PARANOIA */ + if (strcmp(namep, pwd->pw_passwd)) + invalid = TRUE; + } + /* + * If user not super-user, check for logins disabled. + */ + if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { + while ((c = getc(nlfd)) != EOF) + putchar(c); + fflush(stdout); + sleep(5); + exit(0); + } + /* + * If valid so far and root is logging in, + * see if root logins on this terminal are permitted. + */ + if (!invalid && pwd->pw_uid == 0 && + !ttysecure) { + syslog(LOG_SECURITY, "ROOT LOGIN REFUSED %s", tty); + invalid = TRUE; + } + if (invalid) { + printf("Login incorrect\n"); +/* loseit */ + if (++t >= 5) + { + syslog(LOG_SECURITY, + "REPEATED LOGIN FAILURES %s, %s", + tty, utmp.ut_name); + ioctl(0, TIOCHPCL, (struct sgttyb *) 0); + close(0), close(1), close(2); + sleep(10); + exit(1); + } +/* loseit */ + } + if (*pwd->pw_shell == '\0') + pwd->pw_shell = "/bin/sh"; + if (chdir(pwd->pw_dir) < 0 && !invalid ) { + if (chdir("/") < 0) { + printf("No directory!\n"); + invalid = TRUE; + } else { + printf("No directory! %s\n", + "Logging in with home=/"); + pwd->pw_dir = "/"; + } + } + /* + * Remote login invalid must have been because + * of a restriction of some sort, no extra chances. + */ + if (rflag && invalid) + exit(1); + } while (invalid); +/* committed to login turn off timeout */ + alarm(0); + time(&utmp.ut_time); + t = ttyslot(); + if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) { + lseek(f, (long)(t*sizeof(utmp)), 0); + SCPYN(utmp.ut_line, tty); + write(f, (char *)&utmp, sizeof(utmp)); + close(f); + } + if (t > 0 && (f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) { + write(f, (char *)&utmp, sizeof(utmp)); + close(f); + } + quietlog = access(qlog, F_OK) == 0; + if ((f = open(lastlog, O_RDWR)) >= 0) { + struct lastlog ll; + + lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); + if (read(f, (char *) &ll, sizeof ll) == sizeof ll && + ll.ll_time != 0 && !quietlog) { + printf("Last login: %.*s ", + 24-5, (char *)ctime(&ll.ll_time)); + if (*ll.ll_host != '\0') + printf("from %.*s\n", + sizeof (ll.ll_host), ll.ll_host); + else + printf("on %.*s\n", + sizeof (ll.ll_line), ll.ll_line); + } + lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); + time(&ll.ll_time); + SCPYN(ll.ll_line, tty); + SCPYN(ll.ll_host, utmp.ut_host); + write(f, (char *) &ll, sizeof ll); + close(f); + } + chown(ttyn, pwd->pw_uid, pwd->pw_gid); + chmod(ttyn, 0622); + setgid(pwd->pw_gid); + strncpy(name, utmp.ut_name, NMAX); + name[NMAX] = '\0'; + initgroups(name, pwd->pw_gid); + setuid(pwd->pw_uid); + strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); + strncat(shell, pwd->pw_shell, sizeof(shell)-7); + if (term[strlen("TERM=")] == 0) + strncat(term, stypeof(ttyn), sizeof(term)-6); + strncat(user, pwd->pw_name, sizeof(user)-6); + strncat(logname, pwd->pw_name, sizeof(user)-9); + environ = envinit; + if ((namep = rindex(pwd->pw_shell, '/')) == NULL) + namep = pwd->pw_shell; + else + namep++; + strcat(minusnam, namep); + umask(022); + if (tty[sizeof("tty")-1] == 'd') + syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); + if (pwd->pw_uid == 0) + syslog(LOG_SECURITY, "ROOT LOGIN %s", tty); + if (!quietlog) { + int pid, w; + struct stat st; + + showmotd(); + strcat(maildir, pwd->pw_name); + if (stat(maildir, &st) == 0 && st.st_size != 0) + printf("You have %smail.\n", + (st.st_mtime > st.st_atime) ? "new " : ""); + if ((pid = vfork()) == 0) { + execl(QUOTAWARN, QUOTAWARN, (char *)0); + write(2, CANTRUN, sizeof(CANTRUN)); + _perror(QUOTAWARN); + _exit(127); + } else if (pid == -1) { + fprintf(stderr, CANTRUN); + perror(QUOTAWARN); + } else { + while ((w = wait((int *)NULL)) != pid && w != -1) + ; + } + } + signal(SIGALRM, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGTSTP, SIG_IGN); + execlp(pwd->pw_shell, minusnam, (char *)0); + perror(pwd->pw_shell); + printf("No shell\n"); + exit(0); +} + +getloginname(up) + register struct utmp *up; +{ + register char *namep; + char c; + + while (up->ut_name[0] == '\0') { + namep = up->ut_name; + printf("login: "); + while ((c = getchar()) != '\n') { + if (c == ' ') + c = '_'; + if (c == EOF) + exit(0); + if (namep < up->ut_name+NMAX) + *namep++ = c; + } + } + strncpy(lusername, up->ut_name, NMAX); + lusername[NMAX] = 0; + setpwent(); + if ((pwd = getpwnam(lusername)) == NULL) + pwd = &nouser; + endpwent(); +} + +timedout() +{ + + printf("Login timed out after %d seconds\n", timeout); + exit(0); +} + +int stopmotd; +catch() +{ + + signal(SIGINT, SIG_IGN); + stopmotd++; +} + +rootterm(tty) + char *tty; +{ + register FILE *fd; + char buf[100]; + + if ((fd = fopen(securetty, "r")) == NULL) + return(1); + while (fgets(buf, sizeof buf, fd) != NULL) { + buf[strlen(buf)-1] = '\0'; + if (strcmp(tty, buf) == 0) { + fclose(fd); + return(1); + } + } + fclose(fd); + return(0); +} + +showmotd() +{ + FILE *mf; + register c; + + signal(SIGINT, catch); + if ((mf = fopen("/etc/motd","r")) != NULL) { + while ((c = getc(mf)) != EOF && stopmotd == 0) + putchar(c); + fclose(mf); + } + signal(SIGINT, SIG_IGN); +} + +#undef UNKNOWN +#define UNKNOWN "su" + +char * +stypeof(ttyid) + char *ttyid; +{ + static char typebuf[16]; + char buf[50]; + register FILE *f; + register char *p, *t, *q; + + if (ttyid == NULL) + return (UNKNOWN); + /* + * CJL's kludge to make supdup win: If TERM is supdup, + * preserve TERM and TERMCAP. SUPDUP sets them up the right way. + */ + t = (char *) getenv("TERM"); + + if (t && !strcmp ("supdup", t)) + { + p = (char *) getenv ("TERMCAP"); + if (p) + { + char **ep; + for (ep = envinit; *ep; ep++); + *ep = p-strlen("TERMCAP="); + } + return (t); + } + f = fopen("/etc/ttytype", "r"); + if (f == NULL) + return (UNKNOWN); + /* split off end of name */ + for (p = q = ttyid; *p != 0; p++) + if (*p == '/') + q = p + 1; + + /* scan the file */ + while (fgets(buf, sizeof buf, f) != NULL) { + for (t = buf; *t != ' ' && *t != '\t'; t++) + if (*t == '\0') + goto next; + *t++ = 0; + while (*t == ' ' || *t == '\t') + t++; + for (p = t; *p > ' '; p++) + ; + *p = 0; + if (strcmp(q,t) == 0) { + strcpy(typebuf, buf); + fclose(f); + return (typebuf); + } + next: ; + } + fclose (f); + return (UNKNOWN); +} + +doremotelogin(host) + char *host; +{ + FILE *hostf; + int first = 1; + char domain[256]; + + if (getdomainname(domain, sizeof(domain)) < 0) { + fprintf(stderr, "login: getdomainname system call missing\n"); + goto bad; + } + getstr(rusername, sizeof (rusername), "remuser"); + getstr(lusername, sizeof (lusername), "locuser"); + getstr(term+5, sizeof(term)-5, "Terminal type"); + if (getuid()) { + pwd = &nouser; + goto bad; + } + setpwent(); + pwd = getpwnam(lusername); + endpwent(); + if (pwd == NULL) { + pwd = &nouser; + goto bad; + } + hostf = pwd->pw_uid ? fopen("/etc/hosts.equiv", "r") : 0; +again: + if (hostf) { + char ahost[32]; + int hostmatch, usermatch; + + while (fgets(ahost, sizeof (ahost), hostf)) { + char *user; + + if ((user = index(ahost, '\n')) != 0) + *user++ = '\0'; + if ((user = index(ahost, ' ')) != 0) + *user++ = '\0'; + if (ahost[0] == '+' && ahost[1] == 0) + hostmatch = 1; + else if (ahost[0] == '+' && ahost[1] == '@') + hostmatch = innetgr(ahost + 2, host, + (char *)NULL, domain); + else if (ahost[0] == '-' && ahost[1] == '@') { + if (innetgr(ahost+2, host, (char *)NULL, + domain)) + break; + } + else if (ahost[0] == '-') { + if (!strcmp(host, ahost+1)) + break; + } + else + hostmatch = !strcmp(host, ahost); + if (user) { + if (user[0] == '+' && user[1] == 0) + usermatch = 1; + else if (user[0] == '+' && user[1] == '@') + usermatch = innetgr(user+2, (char *)NULL, + rusername, domain); + else if (user[0] == '-' && user[1] == '@') { + if (innetgr(user+2, (char *)NULL, + rusername, domain)) + break; + } + else if (user[0] == '-') { + if (!strcmp(user+1, rusername)) + break; + } + else + usermatch = !strcmp(user, rusername); + } + else + usermatch = !strcmp(rusername, lusername); + if (hostmatch && usermatch) { + fclose(hostf); + return (1); + } + } + fclose(hostf); + } + if (first == 1) { + char *rhosts = ".rhosts"; + struct stat sbuf; + + first = 0; + if (chdir(pwd->pw_dir) < 0) + goto again; + if (lstat(rhosts, &sbuf) < 0) + goto again; + if ((sbuf.st_mode & S_IFMT) == S_IFLNK) { + printf("login: .rhosts is a soft link.\r\n"); + goto bad; + } + hostf = fopen(rhosts, "r"); + fstat(fileno(hostf), &sbuf); + if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) { + printf("login: Bad .rhosts ownership.\r\n"); + fclose(hostf); + goto bad; + } + goto again; + } +bad: + return (-1); +} + +getstr(buf, cnt, err) + char *buf; + int cnt; + char *err; +{ + char c; + + do { + if (read(0, &c, 1) != 1) + exit(1); + if (--cnt < 0) { + printf("%s too long\r\n", err); + exit(1); + } + *buf++ = c; + } while (c != 0); +} + +char *speeds[] = + { "0", "50", "75", "110", "134", "150", "200", "300", + "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; +#define NSPEEDS (sizeof (speeds) / sizeof (speeds[0])) + +doremoteterm(term, tp) + char *term; + struct sgttyb *tp; +{ + char *cp = index(term, '/'); + register int i; + + if (cp) { + *cp++ = 0; + for (i = 0; i < NSPEEDS; i++) + if (!strcmp(speeds[i], cp)) { + tp->sg_ispeed = tp->sg_ospeed = i; + break; + } + } + tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; +} + +#ifdef 0 +/* Use syslog instead */ +logerr(fmt, a1, a2, a3) + char *fmt, *a1, *a2, *a3; +{ +#ifdef LOGERR + FILE *cons = fopen("/dev/console", "w"); + + if (cons != NULL) { + fprintf(cons, fmt, a1, a2, a3); + fprintf(cons, "\n\r"); + fclose(cons); + } +#endif +} +#endif /* 0 */ diff --git a/contrib/supdup/supdup.c b/contrib/supdup/supdup.c new file mode 100644 index 0000000..f786ed6 --- /dev/null +++ b/contrib/supdup/supdup.c @@ -0,0 +1,1723 @@ +/* + * User supdup program. + * + * Written Jan. 1985 by David Bridgham. Much of the code dealing + * with the network was taken from the telnet user program released + * with 4.2 BSD UNIX. + */ + +/* Define exactly one of TERMCAP or TERMINFO. + * Link with the appropriate TERMINFO or TERMCAP library. + */ + +/* Hacked by Klotz 2/20/89 to remove +%TDORS from init string. + * Hacked by Klotz 12/19/88 added response to TDORS. + * Hacked by Mly 9-Jul-87 to improve reading of supdup escape commands + * Hacked by Mly July 1987 to do bottom-of-screen cursor-positioning hacks + * when escape char is typed + * Hacked by Mly 29-Aug-87 to nuke stupid auto_right_margin lossage. + + * TODO: Meta, Super, Hyper prefix keys. + * Deal with lossage when running on very narrow screen + * (Things like "SUPDUP command ->" should truncate) + * Defer printing message at bottom of screen if input chars are pending + * Try multiple other host addresses if first fails. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "supdup.h" + +#ifdef TERMINFO +#include +#endif /* TERMINFO */ + +#ifdef TERMCAP +#include /* Kludge assumption: BSDish system */ + +extern char *tgetstr(); + +#include "termcaps.h" /* Get table of term caps we want */ + +static char tspace[2048], *aoftspace; + +#define OUTSTRING_BUFSIZ 2048 +unsigned char *outstring; + +unsigned char *tparam(), *tgoto(); +#endif /* TERMCAP */ + +#define TBUFSIZ 1024 +unsigned char ttyobuf[TBUFSIZ], *ttyfrontp = ttyobuf; +unsigned char netobuf[TBUFSIZ], *netfrontp = netobuf; + +unsigned char hisopts[256]; +unsigned char myopts[256]; + + +int connected = 0; + +/* fd of network connection */ +int net; + +int showoptions = 0; +int options; + +int debug = 0; +FILE *tdebug_file = 0; /* For debugging terminal output */ +FILE *indebug_file = 0; /* For debugging network input */ +#define TDEBUG_FILENAME "supdup-trmout" +#define INDEBUG_FILENAME "supdup-netin" + +/* 0377 if terminal has a meta-key */ +int mask = 0177; +int high_bits = 0; +/* user supdup command-escaper character */ +unsigned char escape_char = ('^'&037); +/* As opposed to winningly-wrap */ +int do_losingly_scroll = 0; + +#if 0 /* brain death */ +int crmod = 0; +#endif /* 0 */ + +/* jmp_buf toplevel; */ +jmp_buf peerdied; + +extern int errno; + +/* Impoverished un*x keyboards */ +#define Ctl(c) ((c)&037) + +int sd (), quit (), rlogout (), suspend (), help (); +int setescape (), status (); +int top (); +#if 0 +int setcrmod (), setdebug (), setoptions (); +#endif /* 0 */ + +struct cmd + { + unsigned char name; /* command name */ + char *help; /* help string */ + int (*handler)(); /* routine which executes command */ + }; + +struct cmd cmdtab[] = + { + /* also q */ + { 'l', "logout connection and quit", rlogout }, + { 'c', "close connection and exit", quit }, + /* also c-z */ + { 'p', "suspend supdup", suspend }, + { 'e', "set escape character", setescape }, + { 't', "set \"top\" bit on next character", top }, + { 's', "print status information", status }, + /* also c-h */ + { '?', "print help information", help }, +#if 0 + { 'r', "toggle mapping of received carriage returns", setcrmod }, + { 'd', "toggle debugging", setdebug }, + { 'v', "toggle viewing of options processing", setoptions }, +#endif /* 0 */ + 0 + }; + +int currcol, currline; /* Current cursor position */ + +struct sockaddr_in tsin; + +void intr(int), deadpeer(int); +char *key_name (); +struct cmd *getcmd (); +struct servent *sp; + +struct tchars otc; +struct ltchars oltc; +struct sgttyb ottyb; + + +putch (c) + register int c; +{ + *ttyfrontp++ = c; + /*>>>>> LOSES if overflows */ +} + + +put_newline () +{ +#ifdef TERMINFO + if (newline) + tputs (newline, 1, putch); +#else +#ifdef TERMCAP + if (fresh_line) + tputs (fresh_line, 1, putch); +#endif /* TERMCAP */ +#endif /* TERMINFO */ + else + { + if (carriage_return) + tputs (carriage_return, 0, putch); + else + putch ('\r'); + if (cursor_down) + tputs (cursor_down, 0, putch); + else + putch ('\n'); + } + ttyoflush (); +} + +#ifdef TERMINFO +#define term_goto(c, l) \ + tputs (tparm (cursor_address, l, c), lines, putch) +#endif /* TERMINFO */ +#ifdef TERMCAP +#define term_goto(c, l) \ + tputs (tgoto (cursor_address, c, l), lines, putch) +#endif /* TERMCAP */ + +char *hostname; + +void +get_host (name) + char *name; +{ + register struct hostent *host; + host = gethostbyname (name); + if (host) + { + tsin.sin_family = host->h_addrtype; +#ifdef notdef + bcopy (host->h_addr_list[0], (caddr_t) &tsin.sin_addr, host->h_length); +#else + bcopy (host->h_addr, (caddr_t) &tsin.sin_addr, host->h_length); +#endif /* h_addr */ + hostname = host->h_name; + } + else + { + tsin.sin_family = AF_INET; + tsin.sin_addr.s_addr = inet_addr (name); + if (tsin.sin_addr.s_addr == -1) + hostname = 0; + else + hostname = name; + } +} + +main (argc, argv) + int argc; + char *argv[]; +{ + sp = getservbyname ("supdup", "tcp"); + if (sp == 0) + { + fprintf (stderr, "supdup: tcp/supdup: unknown service.\n"); + exit (1); + } + ioctl (0, TIOCGETP, (char *) &ottyb); + ioctl (0, TIOCGETC, (char *) &otc); + ioctl (0, TIOCGLTC, (char *) &oltc); + setbuf (stdin, 0); + setbuf (stdout, 0); + do_losingly_scroll = 0; + if (argc > 1 && (!strcmp (argv[1], "-s") || + !strcmp (argv[1], "-scroll"))) + { + argc--; argv++; + do_losingly_scroll = 1; + } + + if (argc > 1 && (!strcmp (argv[1], "-d") || + !strcmp (argv[1], "-debug"))) + { + argv++; argc--; + debug = 1; + } + if (argc > 1 && (!strcmp (argv[1], "-tdebug"))) + { + argv++; argc--; + tdebug_file = fopen(TDEBUG_FILENAME, "wb"); /* Open for binary write */ + if (tdebug_file == NULL) + { + fprintf (stderr, "Couldn't open debug file %s\n", + TDEBUG_FILENAME); + exit (1); + } + setbuf(tdebug_file, NULL); /* Unbuffered so see if we crash */ + } + + if (argc > 1 && !strcmp (argv[1], "-t")) + { + argv++, argc--; + indebug_file = fopen(INDEBUG_FILENAME, "wb"); /* Open for binary write */ + if (indebug_file == NULL) + { + fprintf (stderr, "Couldn't open debug file %s\n", + INDEBUG_FILENAME); + exit (1); + } + } + + if (argc == 1) + { + char *cp; + char line[200]; + + again: + printf ("Host: "); + if (fgets(line, sizeof(line), stdin) == 0) + { + if (feof (stdin)) + { + clearerr (stdin); + putchar ('\n'); + } + goto again; + } + if (cp = strchr(line, '\n')) + *cp = '\0'; + get_host (line); + if (!hostname) + { + printf ("%s: unknown host.\n", line); + goto again; + } + } + else if (argc > 3) + { + printf ("usage: %s host-name [port] [-scroll]\n", argv[0]); + return; + } + else + { + get_host (argv[1]); + if (!hostname) + { + printf ("%s: unknown host.\n", argv[1]); + exit (1); + } + } + + tsin.sin_port = sp->s_port; + if (argc == 3) + { + tsin.sin_port = atoi (argv[2]); + if (tsin.sin_port <= 0) + { + printf ("%s: bad port number.\n", argv[2]); + return; + } + tsin.sin_port = htons (tsin.sin_port); + } + + net = socket (AF_INET, SOCK_STREAM, 0); + if (net < 0) + { + perror ("supdup: socket"); + return; + } + outstring = (unsigned char *) malloc (OUTSTRING_BUFSIZ); + if (outstring == 0) + { + fprintf (stderr, "Memory exhausted.\n"); + exit (1); + } + sup_term (); + if (debug && setsockopt (net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) + perror ("setsockopt (SO_DEBUG)"); + signal (SIGINT, intr); + signal (SIGPIPE, deadpeer); + printf("Trying %s ...", inet_ntoa (tsin.sin_addr)); + fflush (stdout); + if (connect (net, (struct sockaddr *) &tsin, sizeof (tsin)) < 0) +/* >> Should try other addresses here (like BSD telnet) #ifdef h_addr */ + { + perror ("supdup: connect"); + signal (SIGINT, SIG_DFL); + return; + } + connected = 1; + printf ("Connected to %s.\n", hostname); + printf ("Escape character is \"%s\".", key_name (escape_char)); + fflush (stdout); + (void) mode (1); + if (clr_eos) + tputs (clr_eos, lines - currline, putch); + put_newline (); + if (setjmp (peerdied) == 0) + supdup (net); + ttyoflush (); + (void) mode (0); + fprintf (stderr, "Connection closed by %s.\n", hostname); + exit (0); +} + + +#define INIT_LEN 42 /* Number of bytes to send at initialization */ +static char inits[] = + { + /* -wordcount,,0. should always be -6 */ + 077, 077, -6, 0, 0, 0, + /* TCTYP variable. Always 7 (supdup) */ + 0, 0, 0, 0, 0, 7, + /* TTYOPT variable. %TOMVB %TOMOR %TOLOW %TPCBS */ + 1, 2, 020, 0, 0, 040, + /* Height of screen -- updated later */ + 0, 0, 0, 0, 0, 24, + /* Width of screen minus one -- updated later */ + 0, 0, 0, 0, 0, 79, + /* auto scroll number of lines */ + 0, 0, 0, 0, 0, 1, + /* TTYSMT */ + 0, 0, 0, 0, 0, 0 + }; + +/* + * Initialize the terminal description to be sent when the connection is + * opened. + */ +sup_term () +{ +#ifdef TERMINFO + int errret; + + setupterm (0, 1, &errret); + if (errret == -1) + { + fprintf (stderr, "Bad terminfo database.\n"); + exit (1); + } + else if (errret == 0) + { + fprintf (stderr, "Unknown terminal type.\n"); + exit (1); + } +#endif /* TERMINFO */ +#ifdef TERMCAP + static void zap(); + static char bp[2000]; + + switch (systgetent (bp)) + { + case 1: + if (tdebug_file) + fprintf(tdebug_file, "TERMCAP data: %s\n", bp); + zap (); + break; + + case 0: + fprintf (stderr, "Invalid terminal.\n"); + exit (1); + + case -1: + fprintf (stderr, "Can't open termcap file.\n"); + exit (1); + } +#endif /* TERMCAP */ + + if (columns <= 1) { + int badcols = columns; + fprintf (stderr, "supdup: bogus # columns (%d), using %d\r\n", + badcols, columns = 80); + } + +/* + *if (!cursor_address) + * { + * fprintf (stderr, "Can't position cursor on this terminal.\n"); + * exit (1); + * } + */ + + if (do_losingly_scroll) + if (no_scroll && !SF) + { + fprintf (stderr, "(Terminal won't scroll. Hah!!)\n"); + do_losingly_scroll = 0; + } + else + inits[13] |= 01; + + inits[23] = lines & 077; + inits[22] = (lines >> 6) & 077; + { + register int w; + + if (auto_right_margin) + /* Brain death! Can't write in last column of last line + * for fear that stupid terminal will scroll up. Glag. */ + columns = columns - 1; + + /* Silly SUPDUP spec says that should specify (1- columns) */ + w = columns - 1; + inits[29] = w & 077; + inits[28] = (w >> 6) & 077; + } + if (clr_eol) inits[12] |= 04; + if (over_strike) inits[13] |= 010; + if (cursor_address) inits[13] |= 04; + if (has_meta_key || also_has_meta_key) + { + /* %TOFCI */ +/* Don't do this -- it implies that we can generate full MIT 12-bit */ +/* inits[14] |= 010; */ + mask = 0377; + } + if ((delete_line || parm_delete_line) && + (insert_line || parm_insert_line)) + inits[14] |= 02; + if ((delete_character || parm_dch) && + (insert_character || parm_ich)) + inits[14] |= 01; +} + +#ifdef TERMCAP +static void zap () +{ + unsigned char *fp, **sp; + char *namp; + int *np; + int i; + struct tcent *tc = tcaptab; + + aoftspace = tspace; + + for (i = 0; i < (sizeof(tcaptab)/sizeof(tcaptab[0])); ++i, ++tc) { + switch (tc->tctyp) { + case TCTYP_STR: + tc->tcval.str = tgetstr(tc->tcname, &aoftspace); + if (tdebug_file) + fprintf(tdebug_file, "str %s: %s\n", + tc->tcname, (tc->tcval.str ? tc->tcval.str : "-null-")); + break; + case TCTYP_NUM: + tc->tcval.num = tgetnum(tc->tcname); + if (tdebug_file) + fprintf(tdebug_file, "num %s: %d\n", + tc->tcname, tc->tcval.num); + break; + case TCTYP_FLG: + tc->tcval.flg = tgetflag(tc->tcname); + if (tdebug_file) + fprintf(tdebug_file, "flg %s: %s\n", + tc->tcname, (tc->tcval.flg ? "true" : "false")); + break; + default: + fprintf(stderr,"supdup: unknown termcap \"%s\"\n", + tcaptab[i].tcname); + continue; + } + } + + +/* + if (!cursor_left) + cursor_left = "\b"; + if (!carriage_return) + carriage_return = "\r"; + if (!cursor_down) + cursor_down = "\n"; +*/ + +} + +extern char *getenv (); + +systgetent (bp) + char *bp; +{ + register char *term; + + if (term = getenv ("TERM")) + return tgetent (bp, term); + else + return 0; +} +#endif /* TERMCAP */ + +struct tchars notc = { -1, -1, -1, -1, -1, -1 }; +struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; + +mode (f) + register int f; +{ + static int prevmode = 0; + struct tchars *tc; + struct ltchars *ltc; + struct sgttyb sb; + int onoff, old; + + if (prevmode == f) + return (f); + old = prevmode; + prevmode = f; + sb = ottyb; + switch (f) + { + case 0: + onoff = 0; + tc = &otc; + ltc = &oltc; + break; + + default: + sb.sg_flags |= RAW; /* was CBREAK */ + sb.sg_flags &= ~(ECHO|CRMOD); + sb.sg_flags |= LITOUT; +#ifdef PASS8 + sb.sg_flags |= PASS8; +#endif + sb.sg_erase = sb.sg_kill = -1; + tc = ¬c; + ltc = &noltc; + onoff = 1; + break; + } + ioctl (fileno (stdin), TIOCSLTC, (char *) ltc); + ioctl (fileno (stdin), TIOCSETC, (char *) tc); + ioctl (fileno (stdin), TIOCSETP, (char *) &sb); + ioctl (fileno (stdin), FIONBIO, &onoff); + ioctl (fileno (stdout), FIONBIO, &onoff); + return (old); +} + +unsigned char sibuf[TBUFSIZ], *sbp; +unsigned char tibuf[TBUFSIZ], *tbp; +int scc; +int tcc; + +int escape_seen; +int saved_col, saved_row; + +void +restore () +{ + if (cursor_address) + { + if ((escape_seen & 1) != 0) + { + term_goto (0, currline); + if (clr_eos) + tputs (clr_eos, lines - currline, putch); + } + term_goto (currcol = saved_col, currline = saved_row); + } + escape_seen = 0; + ttyoflush (); +} + +void +clear_bottom_line () +{ + if (LL || cursor_address) + { + currcol = 0; currline = lines - 1; + if (LL) + tputs (LL, 1, putch); + else + term_goto (currcol, currline); + if (clr_eol) + tputs (clr_eol, columns, putch); + } + ttyoflush (); +} + +int +read_char () +{ + int readfds; + + while (1) + { + tcc = read (fileno (stdin), tibuf, 1); + if (tcc >= 0 || errno != EWOULDBLOCK) + { + register int c = (tcc <= 0) ? -1 : tibuf[0]; + tcc = 0; tbp = tibuf; + return (c); + } + else + { + readfds = 1 << fileno (stdin); + select(32, &readfds, 0, 0, 0, 0); + } + } +} + + +/* + * Select from tty and network... + */ +supdup () +{ + register int c; + int tin = fileno (stdin), tout = fileno (stdout); + int on = 1; + + ioctl (net, FIONBIO, &on); + + for (c = 0; c < INIT_LEN;) + *netfrontp++ = inits[c++]; + +#ifdef TERMCAP + if (VS) tputs (VS, 0, putch); +#endif /* TERMCAP */ + scc = 0; + tcc = 0; + escape_seen = 0; + for (;;) + { + int ibits = 0, obits = 0; + + if (netfrontp != netobuf) + obits |= (1 << net); + else + ibits |= (1 << tin); + if (ttyfrontp != ttyobuf) + obits |= (1 << tout); + else + ibits |= (1 << net); + if (scc < 0 && tcc < 0) + break; + select (16, &ibits, &obits, 0, 0); + if (ibits == 0 && obits == 0) + { + sleep (5); + continue; + } + + /* + * Something to read from the network... + */ + if ((escape_seen == 0) && (ibits & (1 << net))) + { + scc = read (net, sibuf, sizeof (sibuf)); + if (scc < 0 && errno == EWOULDBLOCK) + scc = 0; + else + { + if (scc <= 0) + break; + sbp = sibuf; + if (indebug_file) + fwrite(sibuf, scc, 1, indebug_file); + } + } + + /* + * Something to read from the tty... + */ + if (ibits & (1 << tin)) + { + tcc = read (tin, tibuf, sizeof (tibuf)); + if (tcc < 0 && errno == EWOULDBLOCK) + tcc = 0; + else + { + if (tcc <= 0) + break; + tbp = tibuf; + } + } + + while (tcc > 0) + { + register int c; + + if ((&netobuf[sizeof(netobuf)] - netfrontp) < 2) + break; + c = *tbp++ & mask; tcc--; + if (escape_seen > 2) + { + /* ``restore'' the screen (or at least the cursorpos) */ + restore (); + } + else if (escape_seen > 0) + { + escape_seen = escape_seen + 2; + command (c); + continue; + } + + if (c == escape_char) + { + escape_seen = (tcc == 0) ? 1 : 2; + saved_col = currcol; + saved_row = currline; + if (tcc == 0) + { + clear_bottom_line (); + fprintf (stdout, "SUPDUP %s command -> ", hostname); + ttyoflush (); + } + continue; + } + + if (c & 0200) + { + high_bits = 2; + c &= 0177; + } + if ((c & 0140) == 0) + { + switch (c) + { + case 010: + case 011: + case 012: + case 013: + case 014: + case 015: + case 032: + case 033: + case 037: + break; + default: + high_bits |= 1; + c = c + '@'; + break; + } + } + if (high_bits) + { + *netfrontp++ = ITP_ESCAPE; + *netfrontp++ = high_bits + 0100; + high_bits = 0; + } + *netfrontp++ = c; + } + if ((obits & (1 << net)) && (netfrontp != netobuf)) + netflush (0); + if (scc > 0) + suprcv (); + if ((obits & (1 << tout)) && (ttyfrontp != ttyobuf)) + ttyoflush (); + } +} + + +command (chr) + unsigned char chr; +{ + register struct cmd *c; + + /* flush typeahead */ + tcc = 0; + if (chr == escape_char) + { + *netfrontp++ = chr; + restore (); + return; + } + + for (c = cmdtab; c->name; c++) + if (c->name == chr) + break; + + if (!c->name && (chr >= 'A' && chr <= 'Z')) + for (c = cmdtab; c->name; c++) + if (c->name == (chr - 'A' + 'a')) + break; + + if (c->name) + (*c->handler) (); + else if (chr == '\177' || chr == Ctl ('g')) + restore (); + else if (chr == Ctl ('z')) + suspend (); + else if (chr == Ctl ('h')) + help (); + else if (chr == 'q') + rlogout (); + else + { + clear_bottom_line (); + printf ("?Invalid SUPDUP command \"%s\"", + key_name (chr)); + ttyoflush (); + return; + } + ttyoflush (); + if (!connected) + exit (1); + return; +} + +status () +{ + if (cursor_address) + { + currcol = 0; currline = lines - 3; + term_goto (currcol, currline); + if (clr_eos) + tputs (clr_eos, lines - currline, putch); + } + ttyoflush (); + if (connected) + printf ("Connected to %s.", hostname); + else + printf ("No connection."); + ttyoflush (); + put_newline (); + printf ("Escape character is \"%s\".", key_name (escape_char)); + ttyoflush (); +} + +suspend () +{ + register int save; + + if (cursor_home) + tputs (cursor_home, 1, putch); + else if (cursor_address) + term_goto (0, 0); + if (clr_eol) + tputs (clr_eol, columns, putch); +#ifdef TERMCAP + if (VE) tputs (VE, 0, putch); +#endif /* TERMCAP */ + ttyoflush (); + save = mode (0); + if (!cursor_address) + putchar ('\n'); + kill (0, SIGTSTP); + /* reget parameters in case they were changed */ + ioctl (0, TIOCGETP, (char *) &ottyb); + ioctl (0, TIOCGETC, (char *) &otc); + ioctl (0, TIOCGLTC, (char *) &oltc); + (void) mode (save); +#ifdef TERMCAP + if (VS) tputs (VS, 0, putch); +#endif /* TERMCAP */ + *netfrontp++ = ITP_ESCAPE; /* Tell other end that it sould refresh */ + *netfrontp++ = ITP_PIATY; /* the screen */ + restore (); +} + +/* + * Help command. + */ +help () +{ + register struct cmd *c; + + if (cursor_address) + { + for (c = cmdtab, currline = lines - 1 ; + c->name; + c++, currline--) + ; + currcol = 0; + currline--; /* For pass-through `command' doc */ + term_goto (currcol, currline); + if (clr_eos) + tputs (clr_eos, lines - currline, putch); + } + + ttyoflush (); + printf ("Type \"%s\" followed by the command character. Commands are:", + key_name (escape_char)); + ttyoflush (); + put_newline (); + printf (" %-8s%s", + key_name (escape_char), + "sends escape character through"); + ttyoflush (); + for (c = cmdtab; c->name; c++) + { + put_newline (); + printf (" %-8s%s", + key_name (c->name), + c->help); + } + ttyoflush (); + + { + register int c; + c = read_char (); + restore (); + if (c < 0) + return; + if (c == ' ') + return; + /* unread-char */ + tibuf[0] = c; tcc = 1; tbp = tibuf; + } + return; +} + +punt (logout_p) + int logout_p; +{ + register int c; + + clear_bottom_line (); + /* flush typeahead */ + tcc = 0; + fprintf (stdout, "Quit (and %s from %s)? ", + logout_p ? "logout" : "disconnect", + hostname); + ttyoflush (); + while (1) + { + c = read_char (); + if (c == 'y' || c == 'Y') + break; + else if (c == 'n' || c == 'N' || c == '\177' || c == Ctl ('g')) + { + restore (); + return; + } + } + if (logout_p) + { + netflush (1); + *netfrontp++ = SUPDUP_ESCAPE; + *netfrontp++ = SUPDUP_LOGOUT; + netflush (1); + } + if (cursor_home) + tputs (cursor_home, 1, putch); + else if (cursor_address) + term_goto (0, 0); +#ifdef TERMCAP + if (VE) tputs (VE, 0, putch); +#endif /* TERMCAP */ + ttyoflush (); + (void) mode (0); + if (!cursor_address) + putchar ('\n'); + if (connected) + { + shutdown (net, 2); + printf ("Connection closed.\n"); + ttyoflush (); + close (net); + } + exit (0); +} + +quit () +{ + punt (0); +} + +rlogout () +{ + punt (1); +} + + +/* + * Supdup receiver states for fsm + */ +#define SR_DATA 0 +#define SR_M0 1 +#define SR_M1 2 +#define SR_M2 3 +#define SR_M3 4 +#define SR_QUOTE 5 +#define SR_IL 6 +#define SR_DL 7 +#define SR_IC 8 +#define SR_DC 9 + +suprcv () +{ + register int c; + static int state = SR_DATA; + static int y; + + while (scc > 0) + { + c = *sbp++ & 0377; scc--; + switch (state) + { + case SR_DATA: + if ((c & 0200) == 0) + { + if (currcol < columns) + { + currcol++; + *ttyfrontp++ = c; + } + else + { + /* Supdup (ITP) terminals should `stick' at the end + of `long' lines (ie not do TERMCAP `am') */ + } + continue; + } + else switch (c) + { + case TDMOV: + state = SR_M0; + continue; + case TDMV1: + case TDMV0: + state = SR_M2; + continue; + case TDEOF: + if (clr_eos) + tputs (clr_eos, lines - currline, putch); + continue; + case TDEOL: + if (clr_eol) + tputs (clr_eol, columns - currcol, putch); + continue; + case TDDLF: + putch (' '); + goto foo; + case TDBS: + currcol--; + foo: + if (currcol < 0) + currcol = 0; + else if (cursor_left) + tputs (cursor_left, 0, putch); + else if (BS) + putch ('\b'); + else if (cursor_address) + term_goto (currcol, currline); + continue; + case TDCR: + currcol = 0; + if (carriage_return) + tputs (carriage_return, 0, putch); + else if (cursor_address) + term_goto (currcol, currline); + else + putch ('\r'); + continue; + case TDLF: + currline++; + if (currline >= lines) + currline--; + else if (cursor_down) + tputs (cursor_down, 0, putch); + else if (cursor_address) + term_goto (currcol, currline); + else + putch ('\n'); + continue; + case TDCRL: + put_newline (); currcol = 0; + currline++; + if (clr_eol) + tputs (clr_eol, columns - currcol, putch); + continue; + case TDNOP: + continue; + case TDORS: /* ignore interrupts and */ + netflush (0); /* send cursorpos back every time */ + *netfrontp++ = ITP_ESCAPE; + *netfrontp++ = ITP_CURSORPOS; + *netfrontp++ = ((unsigned char) currline); + *netfrontp++ = ((unsigned char) currcol); + netflush (0); + continue; + case TDQOT: + state = SR_QUOTE; + continue; + case TDFS: + if (currcol < columns) + { + currcol++; + if (cursor_right) + tputs (cursor_right, 1, putch); + else if (cursor_address) + term_goto (currcol, currline); + else + currcol--; + } + continue; + case TDCLR: + currcol = 0; + currline = 0; + if (clear_screen) + tputs (clear_screen, lines, putch); + else + { + if (cursor_home) + tputs (cursor_home, 1, putch); + else if (cursor_address) + term_goto (0, 0); + if (clr_eos) + tputs (clr_eos, lines, putch); + } + continue; + case TDBEL: + if (flash_screen) + tputs (flash_screen, 0, putch); + else if (bell) + tputs (bell, 0, putch); + else + /* >>>> ?? */ + putch ('\007'); + continue; + case TDILP: + state = SR_IL; + continue; + case TDDLP: + state = SR_DL; + continue; + case TDICP: + state = SR_IC; + continue; + case TDDCP: + state = SR_DC; + continue; + case TDBOW: + if (enter_standout_mode) + tputs (enter_standout_mode, 0, putch); + continue; + case TDRST: + if (exit_standout_mode) + tputs (exit_standout_mode, 0, putch); + continue; + default: + ttyoflush (); + fprintf (stderr, ">>>bad supdup opcode %o ignored<<<", c); + ttyoflush (); + if (cursor_address) + term_goto (currcol, currline); + } + case SR_M0: + state = SR_M1; + continue; + case SR_M1: + state = SR_M2; + continue; + case SR_M2: + y = c; + state = SR_M3; + continue; + case SR_M3: + if (c < columns && y < lines) + { + currcol = c; currline = y; + term_goto (currcol, currline); + } + state = SR_DATA; + continue; + case SR_QUOTE: + putch (c); + state = SR_DATA; + continue; + case SR_IL: + if (parm_insert_line) + { +#ifdef TERMINFO + tputs (tparm (parm_insert_line, c), c, putch); +#endif /* TERMINFO */ +#ifdef TERMCAP + outstring = tparam (parm_insert_line, + outstring, OUTSTRING_BUFSIZ, + c); + tputs (outstring, c, putch); +#endif /* TERMCAP */ + } + else + if (insert_line) + while (c--) + tputs (insert_line, 1, putch); + state = SR_DATA; + continue; + case SR_DL: + if (parm_delete_line) + { +#ifdef TERMINFO + tputs (tparm (parm_delete_line, c), c, putch); +#endif /* TERMINFO */ +#ifdef TERMCAP + outstring = tparam (parm_delete_line, + outstring, OUTSTRING_BUFSIZ, + c); + tputs (outstring, c, putch); +#endif /* TERMCAP */ + } + else + if (delete_line) + while (c--) + tputs (delete_line, 1, putch); + state = SR_DATA; + continue; + case SR_IC: + if (parm_ich) + { +#ifdef TERMINFO + tputs (tparm (parm_ich, c), c, putch); +#endif /* TERMINFO */ +#ifdef TERMCAP + outstring = tparam (parm_ich, + outstring, OUTSTRING_BUFSIZ, + c); + tputs (outstring, c, putch); +#endif /* TERMCAP */ + } + else + if (insert_character) + while (c--) + tputs (insert_character, 1, putch); + state = SR_DATA; + continue; + case SR_DC: + if (parm_dch) + { +#ifdef TERMINFO + tputs (tparm (parm_dch, c), c, putch); +#endif /* TERMINFO */ +#ifdef TERMCAP + outstring = tparam (parm_dch, + outstring, OUTSTRING_BUFSIZ, + c); + tputs (outstring, c, putch); +#endif /* TERMCAP */ + } + else + if (delete_character) + while (c--) + tputs (delete_character, 1, putch); + state = SR_DATA; + continue; + } + } +} + +ttyoflush () +{ + int n; + unsigned char *back = ttyobuf; + + fflush (stdout); + while ((n = ttyfrontp - back) > 0) + { + if (tdebug_file) { + fprintf(tdebug_file, "Outraw %d:[", n); + fwrite(back, n, 1, tdebug_file); + fprintf(tdebug_file, "]\n"); + } + + n = write (fileno (stdout), back, n); +/* fflush (stdout); */ + if (n >= 0) + back += n; + else + if (errno == EWOULDBLOCK) + continue; + else + /* Here I am being a typical un*x programmer and just + ignoring other error codes. + I really hate this environment! + */ + return; + } + ttyfrontp = ttyobuf; +} + +netflush (dont_die) + int dont_die; +{ + int n; + unsigned char *back = netobuf; + + while ((n = netfrontp - back) > 0) + { + n = write (net, back, n); + if (n < 0) + { + if (errno == ENOBUFS || errno == EWOULDBLOCK) + return; + if (dont_die) + return; + (void) mode (0); + perror (hostname); + close (net); + longjmp (peerdied, -1); + /*NOTREACHED*/ + } + back += n; + } + netfrontp = netobuf; +} + + +char key_name_buffer[20]; +char * +key_name (c) + register int c; +{ + register char *p = key_name_buffer; + if (c >= 0200) + { + *p++ = 'M'; + *p++ = '-'; + c -= 0200; + } + if (c < 040) + { + if (c == 033) + { + *p++ = 'E'; + *p++ = 'S'; + *p++ = 'C'; + } + else if (c == Ctl ('I')) + { + *p++ = 'T'; + *p++ = 'A'; + *p++ = 'B'; + } + else if (c == Ctl ('J')) + { + *p++ = 'L'; + *p++ = 'F'; + *p++ = 'D'; + } + else if (c == Ctl ('M')) + { + *p++ = 'R'; + *p++ = 'E'; + *p++ = 'T'; + } + else + { + *p++ = 'C'; + *p++ = '-'; + if (c > 0 && c <= Ctl ('Z')) + *p++ = c + 0140; + else + *p++ = c + 0100; + } + } + else if (c == 0177) + { + *p++ = 'D'; + *p++ = 'E'; + *p++ = 'L'; + } + else if (c == ' ') + { + *p++ = 'S'; + *p++ = 'P'; + *p++ = 'C'; + } + else + *p++ = c; + *p++ = 0; + return (key_name_buffer); +} + +void deadpeer(int sig) +{ + (void) mode (0); + longjmp (peerdied, -1); +} + +void intr (int sig) +{ + (void) mode (0); + exit (1); +} + +top () +{ + high_bits |= 020; + restore (); +} + +/* + * Set the escape character. + */ +setescape () +{ + clear_bottom_line (); + printf ("Type new escape character: "); + ttyoflush (); + escape_char = read_char (); + clear_bottom_line (); + printf ("Escape character is \"%s\".", key_name (escape_char)); + ttyoflush (); +} + +#if 0 +setoptions () +{ + showoptions = !showoptions; + clear_bottom_line (); + printf ("%s show option processing.", showoptions ? "Will" : "Wont"); + ttyoflush (); +} +#endif /* 0 */ + +#if 0 +/* >>>>>> ???!! >>>>>> */ +setcrmod () +{ + crmod = !crmod; + clear_bottom_line (); + printf ("%s map carriage return on output.", crmod ? "Will" : "Wont"); + ttyoflush (); +} +#endif /* 0 */ + +#if 0 +setdebug () +{ + debug = !debug; + clear_bottom_line (); + printf ("%s turn on socket level debugging.", debug ? "Will" : "Wont"); + if (debug && net > 0 && setsockopt (net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) + perror ("setsockopt (SO_DEBUG)"); + ttyoflush (); +} +#endif /* 0 */ + + +#ifdef TERMCAP + +/* Assuming STRING is the value of a termcap string entry + containing `%' constructs to expand parameters, + merge in parameter values and store result in block OUTSTRING points to. + LEN is the length of OUTSTRING. If more space is needed, + a block is allocated with `malloc'. + + The value returned is the address of the resulting string. + This may be OUTSTRING or may be the address of a block got with `malloc'. + In the latter case, the caller must free the block. + + The fourth and following args to tparam serve as the parameter values. */ + +static unsigned char *tparam1 (); + +/* VARARGS 2 */ +unsigned char * +tparam (string, outstring, len, arg0, arg1, arg2, arg3) + unsigned char *string; + unsigned char *outstring; + int len; + int arg0, arg1, arg2, arg3; +{ + int arg[4]; + arg[0] = arg0; + arg[1] = arg1; + arg[2] = arg2; + arg[3] = arg3; + return tparam1 (string, outstring, len, 0, 0, arg); +} + +unsigned char *BC; +unsigned char *UP; + +static unsigned char tgoto_buf[50]; + +unsigned char * +tgoto (cm, hpos, vpos) + char *cm; + int hpos, vpos; +{ + int args[2]; + if (!cm) + return 0; + args[0] = vpos; + args[1] = hpos; + return tparam1 (cm, tgoto_buf, 50, UP, BC, args); +} + +static unsigned char * +tparam1 (string, outstring, len, up, left, argp) + unsigned char *string; + unsigned char *outstring; + int len; + unsigned char *up, *left; + register int *argp; +{ + register int c; + register unsigned char *p = string; + register unsigned char *op = outstring; + unsigned char *outend; + int outlen = 0; + + register int tem; + int *oargp = argp; + unsigned char *doleft = 0; + unsigned char *doup = 0; + + outend = outstring + len; + + while (1) + { + /* If the buffer might be too short, make it bigger. */ + if (op + 5 >= outend) + { + register unsigned char *new; + if (outlen == 0) + { + new = (unsigned char *) malloc (outlen = 40 + len); + outend += 40; + } + else + { + outend += outlen; + new = (unsigned char *) realloc (outstring, outlen *= 2); + } + op += new - outstring; + outend += new - outstring; + outstring = new; + } + if (!(c = *p++)) + break; + if (c == '%') + { + c = *p++; + tem = *argp; + switch (c) + { + case 'd': /* %d means output in decimal */ + if (tem < 10) + goto onedigit; + if (tem < 100) + goto twodigit; + case '3': /* %3 means output in decimal, 3 digits. */ + if (tem > 999) + { + *op++ = tem / 1000 + '0'; + tem %= 1000; + } + *op++ = tem / 100 + '0'; + case '2': /* %2 means output in decimal, 2 digits. */ + twodigit: + tem %= 100; + *op++ = tem / 10 + '0'; + onedigit: + *op++ = tem % 10 + '0'; + argp++; + break; + + case 'C': + /* For c-100: print quotient of value by 96, if nonzero, + then do like %+ */ + if (tem >= 96) + { + *op++ = tem / 96; + tem %= 96; + } + case '+': /* %+x means add character code of char x */ + tem += *p++; + case '.': /* %. means output as character */ + if (left) + { + /* If want to forbid output of 0 and \n, + and this is one, increment it. */ + if (tem == 0 || tem == '\n') + { + tem++; + if (argp == oargp) + outend -= strlen (doleft = left); + else + outend -= strlen (doup = up); + } + } + *op++ = tem; + case 'f': /* %f means discard next arg */ + argp++; + break; + + case 'b': /* %b means back up one arg (and re-use it) */ + argp--; + break; + + case 'r': /* %r means interchange following two args */ + argp[0] = argp[1]; + argp[1] = tem; + oargp++; + break; + + case '>': /* %>xy means if arg is > char code of x, */ + if (argp[0] > *p++) /* then add char code of y to the arg, */ + argp[0] += *p; /* and in any case don't output. */ + p++; /* Leave the arg to be output later. */ + break; + + case 'a': /* %a means arithmetic */ + /* Next character says what operation. + Add or subtract either a constant or some other arg */ + /* First following character is + to add or - to subtract + or = to assign. */ + /* Next following char is 'p' and an arg spec + (0100 plus position of that arg relative to this one) + or 'c' and a constant stored in a character */ + tem = p[2] & 0177; + if (p[1] == 'p') + tem = argp[tem - 0100]; + if (p[0] == '-') + argp[0] -= tem; + else if (p[0] == '+') + argp[0] += tem; + else if (p[0] == '*') + argp[0] *= tem; + else if (p[0] == '/') + argp[0] /= tem; + else + argp[0] = tem; + + p += 3; + break; + + case 'i': /* %i means add one to arg, */ + argp[0] ++; /* and leave it to be output later. */ + argp[1] ++; /* Increment the following arg, too! */ + break; + + case '%': /* %% means output %; no arg. */ + goto ordinary; + + case 'n': /* %n means xor each of next two args with 140 */ + argp[0] ^= 0140; + argp[1] ^= 0140; + break; + + case 'm': /* %m means xor each of next two args with 177 */ + argp[0] ^= 0177; + argp[1] ^= 0177; + break; + + case 'B': /* %B means express arg as BCD char code. */ + argp[0] += 6 * (tem / 10); + break; + + case 'D': /* %D means weird Delta Data transformation */ + argp[0] -= 2 * (tem % 16); + break; + } + } + else + /* Ordinary character in the argument string. */ + ordinary: + *op++ = c; + } + *op = 0; + if (doleft) + strcpy (op, doleft); + if (doup) + strcpy (op, doup); + return outstring; +} +#endif /* TERMCAP */ + diff --git a/contrib/supdup/supdup.h b/contrib/supdup/supdup.h new file mode 100644 index 0000000..52fb0ba --- /dev/null +++ b/contrib/supdup/supdup.h @@ -0,0 +1,111 @@ +/* + * Characters output from user programs are checked for \b, \r, and \n. + * These are translated into SUPDUP cursor movement. Thus this disallows + * the use of these 3 SAIL characters. + * SUPDUP display codes are passed through, but looked at to determine + * the current cursor position. This is necessary for simulating \b, \n, \r + * and the TDBS and TDUP fake SUPDUP codes supplied in the termcap entries. + * Input from the network is checked for ITP escapes, mainly for bucky + * bits and terminal location string. + */ + +/* Losing unix doesn't know about the -real- control bit + + * there should be some way to conditionalize this on the basis + * of %TOFCI -- except that the existing supdup server loses this information! + * It isn't clear-cut what to do in the server, as %tofci means that the user + * can generate full 9-bit MIT characters, which isn't what the `km' termcap + * flag means. On the other hand, being able to generate 8-bit characters + * (which is sort of what `km' is) isn't the same as %tofci. + * I think the problem is fundamental and cultural and irresolvable. + + * unix supdup server uses 0237 as a control escape. + * c-a 001 + * m-a 341 + * c-m-a 201 + * c-1 237 061 + * m-1 261 + * c-m-1 237 261 + * c-m-_ 237 237 + */ + +/* + * Since various parts of UNIX just can't hack the 0200 bit, we define + * a fake lead-in escape - 0177, to avoid a sail graphic that is used + * sometimes... + */ +#define KLUDGE_ESCAPE 0177 + +/* ITP bits (from the 12-bit character set */ +#define ITP_ASCII 00177 /* ascii part of character */ +#define ITP_CTL 00200 /* CONTROL key depressed */ +#define ITP_MTA 00400 /* META key depressed */ +#define ITP_TOP 04000 /* TOP key depressed */ +#define CTL_PREFIX 0237 /* c-m-_ is control prefix */ +#define ITP_CHAR(char1,char2) (((char1 & 037) << 7) + char2) +#define ITP_ESCAPE 034 /* ITS ITP codes follow */ + +#define ITP_CURSORPOS 020 /* user sends vpos/hpos */ +#define ITP_FLOW_CONTROL_START 032 /* Set buffer to zero -- ignored */ +#define ITP_FLOW_CONTROL_INCREASE 001 /* increase buffer size -- ignored */ +#define ITP_FLOW_CONTROL_END 009 /* Set buffer to infinity -- ignored */ +#define ITP_PIATY 003 /* user says her screen is messed-up + we don't (can't) hack this */ +#define ITP_STOP_OUTPUT 023 /* Ignore it */ +#define ITP_RESTART_OUTPUT 022 /* Ignore it */ + +#define ASCII_CTL_MASK ~(0177-037) +#define ASCII_ESCAPE 033 +#define ASCII_PART(char) (char & ITP_ASCII) + +#define SUPDUP_ESCAPE 0300 +#define SUPDUP_LOGOUT 0301 +#define SUPDUP_LOCATION 0302 +#define SUPDUP_ESCAPE_KEY 04101 +#define SUPDUP_SUSPEND_KEY 04102 +#define SUPDUP_CLEAR_KEY 04103 +#define SUPDUP_HELP_KEY 04110 + +#define TDMOV 0200 +#define TDMV1 0201 /* not defined in supdup spec AIM 644 */ +#define TDEOF 0202 +#define TDEOL 0203 +#define TDDLF 0204 +#define TDCRL 0207 +#define TDNOP 0210 +#define TDBS 0211 /* not defined in supdup spec AIM 644 */ +#define TDLF 0212 /* not defined in supdup spec AIM 644 */ +#define TDCR 0213 /* not defined in supdup spec AIM 644 */ +#define TDORS 0214 +#define TDQOT 0215 +#define TDFS 0216 +#define TDMV0 0217 +#define TDCLR 0220 +#define TDBEL 0221 +#define TDILP 0223 +#define TDDLP 0224 +#define TDICP 0225 +#define TDDCP 0226 +#define TDBOW 0227 +#define TDRST 0230 +#define TDGRF 0231 +#define TDSCU 0232 /* Scroll region up */ +#define TDSCD 0233 /* Scroll region down */ + +#define TDUP 0237 /* Interpreted locally, not in supdup spec at all */ + +/* These variables are set at initial connection time */ +char ttyopt[6]; +#define TOERS (ttyopt[0] & 4) /* Terminal can erase */ +#define TOMVB (ttyopt[0] & 1) /* can move backwards */ +#define TOOVR (ttyopt[1] & 010) /* Over printing */ +#define TOMVU (ttyopt[1] & 4) /* can move up */ +#define TOFCI (ttyopt[2] & 010) /* Terminal can transmit full 12-bit MIT ascii */ +#define TOLID (ttyopt[2] & 2) /* Line insert/delete */ +#define TOCID (ttyopt[2] & 1) /* Character insert/delete */ +#define TOSA1 (ttyopt[1] & 020) /* send SAIL characters direct */ +#define TOMOR (ttyopt[1] & 2) /* Do more processing */ +#define TOROL (ttyopt[1] & 1) /* Do scrolling */ +#define TPPRN (ttyopt[4] & 2) /* Swap parens and brackets (ignored)*/ +short ttyrol; /* How much the terminal scrolls by */ + diff --git a/contrib/supdup/supdup.mss b/contrib/supdup/supdup.mss new file mode 100644 index 0000000..c30fa91 --- /dev/null +++ b/contrib/supdup/supdup.mss @@ -0,0 +1,2160 @@ +@make(epap) @comment[-*-scribe-*-] +@case[draft, memo={@textform(memo=(@parm))}, + loser={@textform(memo=())}] +@Style(stringmax=20000) +@case[draft, memo={ + @pageheading(even, right "The SUPDUP Protocol", left "Page @ref(page)") + @pageheading(odd, left "Richard M. Stallman", right "Page @ref(page)")}] +@define(narrow, leftmargin +.25inch, indent 0) +@modify(description, leftmargin +.25inch, indent -.25inch) + +@textform(BigSection=[@memo<@newpage()> + @section(@parm(text))]) + +@begin(TitleBox,Fixed .75inch) + +@case[draft, memo={ +@Center(MASSACHUSETTS INSTITUTE OF TECHNOLOGY +ARTIFICIAL INTELLIGENCE LABORATORY) +@blankspace(.4inches) +@flushleft(AI Memo 644@>@Value(Date)) +@blankspace(.5inches) + +@Majorheading(The SUPDUP Protocol) +@MajorHeading(by) +@MajorHeading(Richard M. Stallman)}, +loser={ +@modify(majorheading,below 0) +@modify(heading,Above 0.6cm) +@MajorHeading(The SUPDUP Protocol) +@Heading(Richard M. Stallman +Artificial Intelligence Lab +Massachusetts Institute of Technology +Cambridge, MA 02139) +}] + +@end(TitleBox) + +@Begin(Abstract) +The SUPDUP protocol provides for login to a remote +system over a network with terminal-independent output, so that only the +local system need know how to handle the user's terminal. +It offers facilities for graphics and for local assistance to +remote text editors. This memo contains a complete description +of the SUPDUP protocol in fullest possible detail. + +@memo< +@B(Keywords:) Communications, Display, Networks. +> +@end(Abstract) + +@Begin(ResearchCredit) +This report describes work done at the Artificial Intelligence Laboratory +of the Massachusetts Institute of Technology. Support for the laboratory's +research is provided in part by the Advanced Research Projects Agency of the +Department of Defense under Office of Naval Research contract N00014-80-C-0505. +@End(ResearchCredit) + +@Unnumbered(Introduction) + +The SUPDUP protocol is a superior replacement for the TELNET protocol. +Its name means "Super Duper". + +The basic purpose of the two protocols is the same: allow a user to log +in to a remote system connected to his local system by a network, as if +his terminal were directly connected to the remote system. Both +protocols define a "virtual terminal" which the remote system is +expected to use. The difference is that TELNET's "Network Virtual +Terminal" is an obsolete teletype, whereas SUPDUP's virtual terminal is +a display, capable (optionally) of powerful operations on +text, drawing pictures, and invisibly sharing the work of a text editor +running on the computer, all totally under the computer's control. + +The cost associated with SUPDUP is that the remote system must be +capable of communicating with SUPDUP's virtual terminal. +Most operating systems understand nothing more than simple printing +terminals, leaving everything else to user programs. The SUPDUP virtual +display terminal is not a superset of the simple printing terminal, so +these operating systems cannot serve as the remote system for SUPDUP. +They can support user programs which make SUPDUP connections to other +systems. Since these operating systems have the deficiency that every +user program which does display must know the details of operation of +each type of terminal to be used, they are inferior anyway; a modern +operating system which provides terminal-independent display support +will have no trouble supporting SUPDUP, or anything like SUPDUP. + + +SUPDUP can operate over any pair of streams which transmit 8-bit +bytes. + +The SUPDUP protocol was created initially by taking the formats +of data in the terminal input and output buffers of ITS,@footnote(The +Incompatible Timesharing System) and the ITS terminal characteristics +words. It has grown by layer on layer of extensions, and ought to be +redesigned from scratch for simplicity. If you do not need to +communicate with systems that support the existing SUPDUP protocol, +you might as well design the low-level details anew. The higher level +design decisions of SUPDUP are reasonably good to follow. + +All numbers except number of bits are octal unless followed by a +decimal point; thus, 12 and 10@. are the same. +Bits in a word are numbered in decimal from the sign bit (bit 0) to +the least significant bit (bit 35, in a 36-bit word). Sizes of words +and fields are also decimal. + +Data words, and bits and fields within them, are referred to by the +names that are conventional on ITS. The names of bits and fields are +those provided for assembler language programs on ITS. + +@Section[SUPDUP Initialization] + +A SUPDUP connection is created using the standard connection-creation +mechanism for the network in use. For the Arpanet, this is the ICP. +For the Chaosnet, this would be the exchange of an RFC, an OPN and a +STS packet. The SUPDUP protocol itself becomes concerned only after +this has been done. + +The initialization of a SUPDUP connection involves sending terminal +characteristics information to the remote system and a greeting +message to the local system. The greeting message is ASCII text, one +character per byte, terminated with a %TDNOP code (see below). It +should simply be printed on the console by the local system. The +terminal characteristics information is made up of several 36-bit +words, which are precisely the internal terminal characteristics words +of ITS. Each word is +broken up into 6 6-bit bytes, which are sent most significant first, +each in one 8-bit byte. The words are + +@enumerate[ +A count. The high 18 bits of this word contain minus the number of +words that follow. This permits new words of terminal characteristics +to be defined without requiring all local-system SUPDUP programs to +be changed. The server will supply a default value for any +characteristics words defined in the future and not mentioned below. + +The TCTYP variable. This should always contain 7. If the server is an +ITS, this tells it to assume that its terminal is a SUPDUP virtual +terminal. + +The TTYOPT variable. This contains many bits and fields. + +The height of the screen. + +The width of the screen minus one. The reason that one is subtracted is +that if one column is used (as on ITS) to indicate line continuation, +this is the effective width of the screen for the user's text. + +The number of lines by which the terminal will scroll automatically if an attempt is +made to Linefeed past the bottom of the screen. This value +is under the control of the physical terminal being used, +but the local system is expected to know the value by virtue +of knowing what type of terminal is in use. It then informs +the remote system by passing this value. For most terminals, +this should be 1. + +The TTYSMT variable. This contains bits and fields that describe the +graphics and local editing capabilities of the terminal. +] + +The TTYOPT word contains these bits: + +@description[ + +%TOCLC (bit 2)@\The remote system should convert lower case characters +to upper case. This is the initial value of a user option. If the +local system has such an option as well, the local setting should be +propagated. Otherwise, this bit should be zero. + +%TOERS (bit 3)@\The terminal can erase selectively; +that is, it supports the output commands %TDEOL, %TDDLF, and +optionally %TDEOF (see below). + +%TOMVB (bit 5)@\The terminal can move its cursor backwards. +(When SUPDUP was invented, model 33 teletypes were still in use!) + +%TOSAI (bit 6)@\The terminal can handle codes 000 through 037, and +177, as printing characters. + +%TOSA1 (bit 7)@\The remote system should output codes 000 through 037, +and 177, as themselves, expecting them to be printing characters. +This is the initial value of a user-settable option, and it should not +be set unless %TOSAI is also set. + +%TOOVR (bit 8)@\The terminal can overprint. That is, if two printing +characters are output at the same position with no erasing in between, +they will both be visible. Any terminal which can move the cursor +back and @i[cannot] overprint will be assumed to handle %TDDLF, since +it can do so by means of the sequence Backspace Space Backspace. + +%TOMVU (bit 9)@\The terminal can move its cursor upwards. That is, it +is a display terminal with some form of cursor control. + +%TOMOR (bit 10)@\The remote system should pause, in whatever fashion +it likes to do so, at the bottom of a screen of output. This is the +initial value of a user option, and it should be set to @i[one]. + +%TOROL (bit 11)@\The remote system should scroll, as opposed to wrap +around, when output goes past the bottom of the screen. This is the +initial value of a user option, and can be set whichever way the local +system expects its users to prefer. On ITS, the default is to wrap. + +%TOLWR (bit 13)@\The terminal can generate lower-case characters as +input. + +%TOFCI (bit 14)@\The terminal keyboard has Control and Meta keys and +can generate all the meaningful codes of the 12-bit character code +(see below). + +%TOLID (bit 16)@\The terminal can do insert/delete line; it supports +the %TDILP and %TDDLP commands. + +%TOCID (bit 17)@\The terminal can do insert/delete character; it +supports the %TDICP and %TDDCP commands. + +%TPCBS (bit 30)@\The local system is sending 034-escape sequences on +input. This bit @i[must be set]. + +%TPORS (bit 32)@\The local system should be notified with a %TDORS +when the remote system attempts to abort output. This bit @i[should be +set]. + +%TPRSC (bit 33)@\The local system implements the region-scrolling +commands %TDRSU and %TDRSD, which scroll an arbitrary portion of the +screen. +] + +The TTYSMT variable contains these bits and fields: + +@begin[description] +%TQMCH (bits 0-2)@\CPU type. +1 indicates a PDP-11. 2 indicates an Imlac PDS1. 3 indicates a PDS4. +0 indicates anything else. 4 through 7 are undefined. + +%TQHGT (bits 3-7)@\Character height in pixels, for the SUPDUP Graphics Protocol. +This is the interline spacing for the font used for ordinary character output. +The total usable screen height is this times the screen height in characters +which applies to ordinary character output. + +%TQWID (bits 8-11)@\Character width in pixels, for the font used for +ordinary character output. The total usable screen width in pixels is +this parameter times the screen width in characters, as used for +ordinary character output. + +%TQVIR (bit 12)@\The local system supports virtual coordinates in the +SUPDUP Graphics Protocol. + +%TQBNK (bit 13)@\The local system supports blinking objects in the +SUPDUP Graphics Protocol. + +%TQXOR (bit 14)@\The local system supports XOR mode in the +SUPDUP Graphics Protocol. + +%TQREC (bit 15)@\The local system supports rectangle commands in the +SUPDUP Graphics Protocol. + +%TQSET (bit 16)@\The local system supports multiple object sets in the +SUPDUP Graphics Protocol. + +%TQGRF (bit 17)@\The local system supports the SUPDUP Graphics +Protocol. + +%TRGIN (bit 18)@\The local system supports graphics input in the +SUPDUP Graphics Protocol. + +%TRGHC (bit 19)@\The local system supports a hardcopy output device in the +SUPDUP Graphics Protocol. + +%TRLED (bit 20)@\The local system supports the Local Editing Protocol. + +%TRSCN (bit 21)@\The local system supports scan-line output in the +SUPDUP Graphics Protocol. + +%TRLSV (bits 22-24)@\If this value @i is nonzero, the local system +supports line saving. Furthermore, the largest allowed label is +4@+[@i]. + +%TRANT (bits 25-27)@\If this value @i is nonzero, the local system +supports approximately 4@+[@i] lines of anticipatory output. +@end[description] + +@Section[SUPDUP Input] + +The SUPDUP input language provides for the transmission of MIT +extended ASCII, described in detail below. This is a 12-bit character +code, but not all possible 12-bit codes are assigned a meaning. Some +of those that are not are used as special commands by the local +editing protocol. + +To transmit 12-bit data on an 8-bit connection, it must be encoded. +The encoding used is that the 8-bit byte value 034 is an escape code. +To transmit the value 034, send two 034's. Codes 200 and up are +encoded into sequences starting with 034. Specifically, to encode +@i[m]*200+@i[n], send 034, @i[m]+100, @i[n]. Other sequences starting +with 034 serve other purposes, described below. + +The %TOFCI bit in TTYOPT should be set if the terminal actually has the +ability to generate all the meaningful codes of extended ASCII. If +%TOFCI is zero, SUPDUP input is restricted to a subset which is +essentially ASCII (but 034 must still be encoded as a sequence of two +034's). The Local Editing Protocol assumes that %TOFCI is one, and uses +a 9-bit subset of the 12-bit character set for its editing commands. + +A character in the 12-bit character set is composed of a @i[basic +character], which makes up the bottom 7 bits, and 5 @i[bucky bits]. The +2000 bit and the 1000 bit are currently unused. The 400 bit stands for +the @i[Meta] shift key, and the 200 bit stands for the @i[Control] shift +key. These two bits can be added to any character, and are significant +in editing commands. The 4000 bit is used to extend the set of basic +characters. + +The 7-bit basic character is usually interpreted as an ASCII +character, except that only these codes in the range 0 through 037 are +allowed: + +@itemize[ +Backspace (code 010) + +Tab (code 011) + +Linefeed (code 012) + +VT (code 013) + +Formfeed (code 014) + +Return (code 015) + +Call (code 032) + +Altmode (code 033) + +Backnext (code 037) +] + +Backspace, Tab, Linefeed, Formfeed, and Return were derived from the +ASCII formatting control characters with the same codes, and they will +often echo like those ASCII characters. + +The 4000 bit gives a non-ASCII interpretation to the basic +character. For example, codes 4000 through 4037 are used for +additional printing characters for symbols which are not in ASCII. +They represent the characters produced, on output, by codes 0 through +37 (which, in the SUPDUP output language, must signify printing +characters if they mean anything at all). Local system SUPDUP programs +do not +need to support these characters, and most do not (so we do not list +their pictorial appearances). If the local-system SUPDUP program does +provide +for output of codes 0 through 37 as printing characters, the %TOSAI bit +in TTYOPT should be one. Otherwise, it should not +ever send codes 4000 through 4037 as input. + +4177 is another additional printing character, which is echoed as code +177 (again, used only if %TOSAI is set). 4101, 4102, 4103 and 4110 are +used for four special command keys, which are called @i[escape], +@i[break], @i[clear] and @i[help]. Only @i[help] receives much use. + +All other combinations of the 4000 bit with various basic characters +are used for special purposes of the protocol, or are undefined. +Codes 4105 (4000 plus E) and 4123 (4000 plus S) are used by the Local +Editing Protocol. Code 4124 (4000 plus T) is used by the Line Saving +Protocol. Codes 4130 (4000 plus X) and 4131 (4000 plus Y) are used by +the SUPDUP Graphics Protocol. + +A server system that has no application for MIT extended ASCII should +convert it into ordinary ASCII as follows: +@itemize[ +Discard all but the low 8 bits of the 12-bit character. + +If the 200 bit is set, clear it, and the 100 bit and the 40 bit. Thus, +control-bit plus A is converted into ASCII control-A. +] + +The encoded SUPDUP input consists entirely of byte values less than 200. +Byte values 200 and above are used for special commands that are not +"terminal input". On ITS, these commands are processed by the network +server program, whereas 034 escape sequences are processed by the +system's terminal driver. + +@itemize[ +The two byte sequence 300 301 says to log out the remote job and break +the connection. + +The two byte sequence 300 302 introduces "console location" text. +This text is meant for human consumption, and describes the location +in some sense of the local system or the user's terminal or both. It +is supplied to the remote system so that system can use it to respond +to inquiries about the user's location. The console location text +should be made up of ASCII printing characters, and is terminated with +a zero byte.] + +@Section[SUPDUP Output] + +Once the SUPDUP connection is initialized, all output uses the SUPDUP +output language. In this language, codes 0 through 177 are used only +to represent printing characters which are expected to advance the +cursor one position to the right. Most terminals support only codes +40 through 176, and only those codes will be sent. If the terminal +supports other codes as printing characters, that fact is indicated by +the %TOSAI bit in TTYOPT. In any case, codes 011 +through 015 do @i[not] have their ASCII formatting significance. + +All other output operations are represented by commands with codes +from 200 to 377. Some of these commands are followed by extra argument +bytes. The contents of an argument byte may be anything from 0 to +377, and its meaning is determined by the command +it follows. The traditional names of these commands are six +characters long and start with %TD. The commands are: + +@begin[description] +%TDMOV (code 200)@\Four arguments, the old vertical and horizontal +position followed by the new vertical and horizontal position. Move +the cursor to the new position, assuming that it was at the specified +old position. The local system should forget its opinion of the old +cursor position and use what the %TDMOV says. This would be absurd on +a display terminal; %TDMOV is used only for printing terminals. For +actual displays, %TDMV0 (see below) is used. + +%TDEOF (code 202)@\No arguments. Erase to end of screen. The cursor +does not move. + +%TDEOL (code 203)@\No arguments. Erase to end of line. The cursor +does not move. + +%TDDLF (code 204)@\No arguments. Erase the character after the +cursor. The cursor does not move. + +%TDCRL (code 207)@\No arguments. Advance the cursor to the next line +and clear it. At the bottom of the screen, this is expected to scroll +the text on the screen by a fixed number of lines. The number of +lines the terminal will scroll by is not expected to be under +the control of the remote system. Instead, the TTYROL terminal +characteristics word is used to tell the remote system how many lines +the terminal @i[will] scroll. + +%TDNOP (code 210)@\No arguments. Do nothing. + +%TDORS (code 214)@\No arguments. This command marks the place in the +data stream at which the remote system executed an abort-output +operation. See the next section. + +%TDQOT (code 215)@\One argument, which should be passed on directly to +the terminal. This is used for transmitting 8-bit data, such as a +program being downloaded into a terminal attached to the local system. + +%TDFS (code 216)@\No arguments. Move the cursor right one position. +This could be done just as well with a %TDMV0; %TDFS is used for data +compression. + +%TDMV0 (code 217)@\Two argument bytes: the vertical position and the +horizontal position. Just move the cursor. + +%TDCLR (code 220)@\No arguments. Clear the screen and move the cursor +to the top left corner. + +%TDBEL (code 221)@\No arguments. Ring the terminal's bell. + +%TDINI (code 222)@\No arguments. Informs the terminal that the remote +system has just been started. This is only sent to hard-wired +terminals. Network connections will never receive this command, +because no network connections exist when the system is started. + +%TDILP (code 223)@\One argument, a number. Insert that many blank +lines at the vertical position of the cursor, pushing the following +lines down. The cursor does not move. + +%TDDLP (code 224)@\One argument, a number. Delete that many lines at +the vertical position of the cursor and below, moving the following +lines up, and creating blank lines at the bottom of the screen. The +cursor does not move. + +%TDICP (code 225)@\One argument, a number. Insert that many blank +character positions after the cursor, pushing following text on the +line to the right. The last few positions on the line are pushed off +the right margin and discarded. Other text lines are not affected. +The cursor does not move. + +%TDDCP (code 226)@\One argument, a number. Delete that many character +positions after the cursor, moving following text on the line left to +fill them up, and creating blank positions at the right margin. Other +lines are not affected, and the cursor does not move + +%TDBOW (code 227)@\No arguments. Display printing characters that +follow as white-on-black. + +%TDRST (code 230)@\No arguments. Reset %TDBOW mode and any other such +options as may be defined later. + +%TDGRF (code 231)@\Variable number of arguments. This introduces a +sequence of SUPDUP Graphics Protocol operations. The SUPDUP Graphics +Protocol is documented in a separate section below. + +%TDRSU (code 232)@\Two arguments, the number of lines in the region to +be scrolled, and the number of lines to scroll it by. The region +consisting of the specified number of lines, starting with the line +that the cursor is on, is scrolled up by an amount specified by the +second argument. Lines scrolled out of the top of the region are +lost, and blank lines are created at the bottom of the region. +This operation is equivalent to a %TDDLP at the top of the region +followed by a %TDILP above the place where the blank lines should be +created, above the bottom of the region. However, %TDRSU can avoid +disturbing the lines below the region even momentarily, which looks +better. + +%TDRSD (code 233)@\Two arguments. Like %TDRSU but scrolls the region +down instead of up. +@end[description] + +The Local Editing Protocol introduces several additional %TD codes. See +the section on the Local Editing Protocol for details on implementing +them. + +@description[ +%TDSYN (code 240)@\Do-Local-Echoing. Two arguments, a +resynchronize code from the last resynchronize received, and the +number of input characters received by the remote system since that +resynchronize. If the synchronization constraint is satisfied, the +local system will begin local editing. + +%TDECO (code 241)@\Prepare-for-Local-Editing. No arguments. +Tells the local system to begin sending resynchronizes, which will +enable the remote system to send a %TDSYN. + +@multiple[ +%TDEDF (code 242)@\Define-Char. Normally followed by two argument bytes +which encode a +9-bit input character and a 5-bit function code; the function code +specifies the editing action of the input character when the user types +it. The bottom seven +bits of each byte are taken, and the two are combined (first byte most +significant) into a 14-bit number. The top 5 bits of this number are +the function code. +Function code 37 serves as an escape: a third argument byte follows, +which contains the actual function code. This is how function codes +larger than 37 are specified. + +The other 9 bits are normally the character whose local editing function +is being defined. It is a 12-bit MIT extended ASCII character whose top +three bits are taken as zero. This means that not all 12-bit codes can +be specified; so the local editing protocol only applies to input +characters with codes 777 and below. Any input character which +contains the 4000 bit is always handled remotely. (The 1000 and 2000 +bits are unused in the 12-bit character set.) + +If the terminal does +not have Control and Meta keys, and transmits ASCII (%TOFCI is not +set), %TDEDF will still speak in terms of 9-bit characters. +Definitions specified for 9-bit characters in the range 300 through +337 should be applied to the ASCII control characters 000 through 037. +Definitions for 9-bit characters in the range 040 through 177 should +be applied to the ASCII characters with the same values. + +@tag(caseindirect) +A counterintuitive feature of MIT extended ASCII is that Control-A and +Control-a are two different characters. Their codes are 301 and 341. +Most programs interpret these two characters the same way, and most +editors will want to tell the local system to interpret the two the same +way. In the Local Editing Protocol this is done by defining the +lower-case character with function code 22, which means "use the +definition of a related character". For characters whose basic +character is a lower case letter, the related character used is the +corresponding upper case character. Thus, defining character 341 +(Control-a) with code 22 tells the local system to use the definition of +character 301 (Control-A). For a non-lower-case character with the +Control bit (200) set, the related character is obtained by turning off +bits 200 and 100. Thus, Control-I (311) turns into Tab (011, which is +ASCII Control-I). Code 22 should be used only with lower case characters +and control characters. + +Some function codes are special, and do something other than define a +character. With these, the 9 bits are used to transmit arguments +associated with the operation being performed. Here is how. + +@begin[description] +Code 31@\Set Word Syntax. The syntax is specified for the ASCII +character which is the low 7 bits of the accompanying 9-bit character. +The 200 bit of the 9-bit character says what the syntax @i[is]: if it +is 1, the character is a separator. If it is 0, the character is part +of a word. + +Code 32@\Set Insertion Mode. The 9 bits contain the insertion mode. + +Code 33@\Initialize. The word syntax table is set so that only +letters and digits are part of words. Insertion mode is set to 1. +The fill column is set to 0. All character definitions are set to +code 0 except these: +@begin[itemize] +Lower case letters, with or without Control or Meta, are set to code +22 (use the definition of the related upper case character). These are +characters 140 through 172, 340 through 372, 540 through 572, and 740 +through 772. + +All printing characters except lower case letters are set to code 7 +(self-insert). These are characters 40 through 140, and 173 through 176. + +Digits, with either Control, Meta or both, are set to code 27 (specify +repeat count). These are characters 260 through 271, 460 through 471, +and 660 through 671. + + +@end[itemize] + +Code 34@\Set Margin. The top 2 bits of the 9 say which margin to set: +0, 1, 2, 3 stand for left, top, right, bottom. The remaining 7 bits +specify that margin, as a distance from the actual screen edge behind +it. + +Code 41@\Set Fill Column. The 9 bits contain the value of the fill +column, or zero if there is to be no fill column. + +@end[description] +] +%TDNLE (code 243)@\Stop-Local-Editing. No arguments. + +%TDTSP (code 244)@\Space-for-Tab. No arguments. Used to output spaces +which are part of the representation of an ASCII tab character in the +text being edited. + +%TDCTB (code 245)@\Line-Beginning-Continued. No arguments. States that +the beginning of this screen line is not at the beginning of a line of +the text being edited. + +%TDCTE (code 246)@\Line-End-Continued. No arguments. States that +the line of text which appears on this screen line extends beyond the +end of the screen line. + +%TDMLT (code 247)@\Multi-Position-Char. Two arguments, the width of +the character about to be displayed, and its character code. The +width specifies the number of +character positions, following the cursor, which belong to the +representation of a single +character of the text being edited. This command sequence should be +followed immediately by output to fill up those positions. +] + +The Line Saving Protocol introduces four additional commands: + +@description[ + +%TDSVL (code 250)@\Save-Lines. Three arguments: a number of lines +@i, followed by two 7-bit bytes of label number @i (low byte first). +@i lines starting with the line the cursor is on have their contents +saved under labels @i, @i+1, ... @i+@i-1. + +%TDRSL (code 251)@\Restore-Lines. Three arguments bytes, the same as for +%TDSVL. The contents saved under @i labels starting at label @i are +restored onto the screen on lines starting with the one the cursor is +on. If any of the labels is not defined, one or more Label-Failure +commands are sent to the remote system to report this. + +%TDSSR (code 252)@\Set-Saving-Range. Two arguments which specify the +range of columns of line contents to save and restore in %TDSVL and +%TDRSL. The first argument is the first column to save. The second +is the last column to save, plus one. + +%TDSLL (code 253)@\Set-Local-Label. Two arguments, the low and high +7-bit bytes of a label number. This label number, and numbers +immediately below it, will be used label the saved contents of any +lines pushed off the screen by locally handled editing commands. +] + +One more command is used together with either local editing or line +saving for anticipatory output. + +@description[ +@begin[multiple] +%TDMCI (code 254)@\Move-Cursor-Invisible. One argument, a logical +vertical position which is a 14-bit @i[signed] number transmitted low +7 bits first. Positions the cursor at an invisible line so that +anticipatory text transmission can be done. Output to the invisible +line continues until a cursor motion %TD command is received. + +The specified vertical position +signifies the relationship between the text on this line and that on +the screen: if lines 2 through 20 are in use for editing (according to +the editing margins), then an invisible line with vertical position 30 +contains the text that would appear 10 lines below the last text +actually displayed. This information is for the use of locally-handled +scrolling commands. + +The invisible lines displayed this way will be remembered by the +local system for the use of locally handled scrolling commands, if +the local system can handle any. Also, the contents can be saved +under a label and then restored into actual visibility under the +control of the remote editor. +@end[multiple] + +] + +@Section[Aborting Output in SUPDUP] + +When a SUPDUP server program is asked to abort (discard) output +already transmitted, it sends a %TDORS character. At the same time, +it sends an interrupt to the local system if the +network between them permits this. The local system should keep a +count of the number of such interrupts minus the number of %TDORSes +received. When this count is positive, all output received must be +discarded and only scanned for %TDORSes. It is legitimate for this +count to become negative. + +When the %TDORS is read which decrements the count back to zero, the +local system must transmit the current cursor position to the remote +system. The remote system is waiting for this, because it does not +know how much output the local system actually discarded, and +therefore it does not know where the terminal cursor ended up. The +cursor position is transmitted using a four byte sequence: +034 020 @i @i. The remote system should hold all output and +not transmit any more until this command is received. + +If the network does not provide for interrupts (high-priority messages), +the local system should send the cursor position whenever a %TDORS is +received. + +@Section[Non-Network Terminals] + +SUPDUP can also be used to communicate with directly wired or dial-up +terminals, which we call non-network terminals. The key point of +distinction is that "networks" provide buffering, flow control and +error recovery, so that SUPDUP as used over networks need not be +concerned with these things. When SUPDUP is used with non-network +terminals, they must all be provided for. + +The buffering is provided in the remote system's terminal controller +and in the terminal itself. The flow control, and associated error +recovery, are provided by an extension of the SUPDUP protocol. This +flow control mechanism was inspired by TCP [see TCP] and is +immeasurably superior to the XON/XOFF mechanism by which many +terminals deprive the user of the use of two valuable editing +commands. + +Flow control works by means of an @i[allocation], stored in the remote +system, which is the number of characters which the remote system can +send to the terminal without overloading it. After this many have +been sent, the remote system must cease transmission until it is sent +an input command giving more allocation. The terminal sends this +command when it has made room in its buffer by processing and removing +characters from it. + +To begin using flow control, the terminal should send the sequence 034 +032, which initializes the allocation to zero. Then it should send +the sequence 034 001 @i[n], where @i[n] is the number of characters of +buffer space available for output. This increments the allocation by @i[n]. +Several 034 001 @i[n] sequences can be used to set the allocation to a +value above 177. + +The remote system should remember the allocation it has received and +decrement it each time a character is transmitted. The terminal +should count the number of output characters processed and removed +from the terminal's buffer for output; every so often, another 034 001 +@i[n] sequence should be sent containing the number of characters +processed since the last 034 001 @i[n]. For example, the terminal could +send 034 001 030 each time it processes another 30 characters of +output. By sending this sequence, it gives the remote system +permission to fill up that part of the buffer again. + +This flow control mechanism has the advantage that it introduces no +delay if the buffering capacity does not become full, while never +requiring the remote system to respond quickly to any particular input +signal. An even greater advantage is that it does not impinge on the +character set available for input from the terminal, since it uses the +034 escape mechanism, and 034 can be transmitted with the sequence 034 +034. + +Because line noise can cause allocate commands to be garbled, if the +terminal receives no output for a considerable period of time, it +should send another 034 032 followed by 034 001 @i[n]. This will make +sure that the remote system and the terminal agree on the allocation. +This is the only error recovery provided. To achieve error recovery +for data as well, one must essentially implement a network +protocol over the line. That is beyond the scope of SUPDUP. + +ITS performs an additional encoding on SUPDUP output data over +non-network lines. It encodes the data into 7-bit bytes so that it +can be sent through old terminal controllers which cannot output 8-bit +bytes. Other systems should not need to use this encoding. Codes 0 +through 176 are transmitted as is. Code 177 is transmitted as 177 +followed by 1. Code 2@i[nn] is transmitted as 177 followed by @i[nn]+2. +All cursor positions are transmitted with 1 added to them to reduce +the frequency with which bytes containing zero must be sent; this is +also to avoid problems with old controllers. + +The 300-sequences may not be used as input and the terminal should not +send them. This is because they are normally processed by the network server, +which is not in use for a non-network line. + +@Unnumbered[SUPDUP Graphics Protocol] + +The SUPDUP Graphics Protocol allows pictures to be transmitted and +updated across an ordinary SUPDUP connection, requiring minimal support +from the remote operating system. Its features are + +@itemize[ +It is easy to do simple things. + +Any program on the server host can at any time begin +outputting pictures. No special preparations are needed. + +No additional network connections are needed. Graphics +operations go through the normal text output connection. + +It does not require a network. It is suitable for use with locally +connected intelligent display terminals, and by programs which need not +know whether they are being used locally or remotely. It can be the +universal means of expression of terminal graphics output, for whatever +destination. + +Loss or interpolation of output, due to a "silence" command typed by +the user or to the receipt of a message, does not leave the local +system confused (though it may garble the interrupted picture itself). + +The local system is not required to remember the +internal "semantic" structure of the picture being +displayed, but just the lines and points, or even just bits +in a bit matrix. + +Like the rest of the SUPDUP protocol, SUPDUP Graphics is terminal-independent. +] + +The terminal capabilities associated with the SUPDUP Graphics Protocol are +described by bits and fields in the TTYSMT variable, described above. +One of these bits is %TQGRF, which indicates that the local system is able +to handle the SUPDUP Graphics Protocol in the first place. + +Graphics output is done with one special %TD command, %TDGRF. This +command is followed by any number of graphics operations, which are +characters in the range 0 through 177. These are just the ordinary +printing characters, but in graphics mode they receive a special +interpretation described below. Characters in their role as graphics operations +have symbolic names starting with %GO, such as %GOMVA and %GOELA. +Some graphics operations themselves take arguments, which follow the operations +and are composed of more characters in the range 0 through 177. + +Any character 200 or above leaves graphics mode and then is interpreted +normally as a %TD command. This way, the amount of misinterpretation of output +due to any interruption of a sequence of graphics operations is bounded. +Normally, %TDNOP is used to terminate a sequence of graphics operations. + +Some other %TD commands interact with SUPDUP Graphics. +The %TDRST command should reset all graphics modes to their normal +states, as described below. %TDCLR resets some graphics state information. + +@section[Graphics Coordinates] + + Graphics mode uses a cursor position which is remembered from one +graphics operation to the next while in graphics mode. The graphics +mode cursor is not the same one used by normal type-out: graphics +protocol operations have no effect on the normal type-out cursor, and +normal type-out has no effect on the graphics mode cursor. In +addition, the graphics cursor's position is measured in pixels rather +than in characters. The relationship between the two units (pixels and +characters) is recorded by the %TQHGT and %TQWID fields of the TTYSMT +variable of the terminal, which contain the height and width in pixels +of the box occupied by a normal-size character. The size of the screen in either +dimension is assumed to be the size of a character box times the +number of characters in that direction on the screen. If the screen +is actually bigger than that, the excess may or may not be part of +the visible area; the remote system will not know that it exists, in any +case. + +Each coordinate of the cursor position is a 14-bit signed number, +with zero at the center of the screen. Positive coordinates go up +and to the left. If the screen dimension is even, the visible +negative pixels extend one unit farther than the positive ones, in +proper two's complement fashion. Excessively large values of the +coordinates will be off the screen, but are still meaningful. +These coordinates in units of pixels are called @i[physical +coordinates]. + +Local systems may optionally support @i[virtual coordinates] as well. A +virtual coordinate is still a 14-bit signed number, but instead of being +in units of physical pixels on the terminal, it is assumed that +4000 +octal is the top of the screen or the right edge, while -4000 octal is +the bottom of the screen or the left edge. The terminal is responsible +for scaling virtual coordinates into units of pixels. The %TQVIR bit in +the TTYSMT variable indicates that the local system supports virtual +coordinates. When the remote system wants to use virtual coordinates, it +should send a %GOVIR; to use physical coordinates again, it should send +a %GOPHY. For robustness, every %TDGRF should be followed by a %GOVIR +or %GOPHY right away so that following commands will be interpreted +properly even if the last %GOVIR or %GOPHY was lost. + +The virtual coordinates are based on a square. If the visible +area on the terminal is not a square, then the standard virtual range +should correspond to a square around the center of the screen, and the +rest of the visible area should correspond to virtual coordinates +just beyond the normally visible range. + + Graphics protocol operations take two types of cursor position +arguments, absolute ones and relative ones. Operations that take +position arguments generally have two forms, one for relative position +and one for absolute. A relative address consists of two offsets, +delta-X and delta-Y, from the old cursor position. Each offset is a +7-bit two's complement number occupying one character. An absolute +address consists of two coordinates, the X followed by the Y, each being +14 bits distributed among two characters, with the less significant 7 +bits in the first character. Both types of address set the running +cursor position which will be used by the next address, if it is +relative. + + Relative addresses are +provided for the sake of data compression only. They do not specify a +permanent constraint between points; the local system is not expected to +have the power to remember objects and constraints. Once an object has +been drawn, no record should be kept of how the cursor positions were +specified. + + Although the cursor position on entry to graphics mode remains +set from the last exit, it is wise to reinitialize it with a %GOMVA +operation before any long transfer, to limit the effects of lost output. + +It is perfectly legitimate for parts of objects to go off the screen. +What happens to them is not terribly important, as long as it is not +disastrous, does not interfere with the reckoning of the cursor +position, and does not cause later objects, drawn after the cursor +moves back onto the screen, to be misdrawn. + +@section[Graphics Operations] + +All graphics mode operations have codes between 0 and 177, and symbolic +names which start with %GO. Operations fall into three classes: draw +operations, erase operations, and control operations. The draw operations +have codes running from 100 to 137, while the erase operation codes run +from 140 to 177. The +control operations have codes below 100. + +If an operation takes a cursor position argument, the 20 bit in the +operation code usually says whether the cursor position should be +relative or absolute. The 20 bit is one for an absolute address. + + Operations to draw an object always have counterparts which erase +the same object. On a bit matrix terminal, erasure and drawing are +almost identical operations. On a display list terminal, erasure +involves searching the display list for an object with the specified +characteristics and deleting it from the list. Thus, on such terminals +you can only count on erasing to work if you specify the object to be +erased exactly the same as the object that was drawn. Any terminal +whose %TOERS bit is set must be able to erase to at least this extent. + +For example, there are four operations on lines. They all operate +between the current graphics cursor position and the specified +cursor position argument: + +@itemize[ +%GODLR (code 101) draw line, relative address. + +%GODLA (code 121) draw line, absolute address. + +%GOELR (code 141) erase line, relative address. + +%GOELA (code 161) erase line, absolute address. +] + +Here is how to clear the screen and draw one line. + +@example( +%TDRST ;Reset all graphics modes. +%TDGRF ;Enter graphics. +%GOCLR ;Clear the screen. +%GOMVA xx yy ;Set cursor. +%GODLA xx yy ;Draw line from there. +%TDNOP ;Exit graphics. +) + + Graphics often uses characters. The %GODCH operation is followed +by a string of characters to be output, terminated by a zero. The +characters must be single-position printing characters. On most +terminals, this limits them to ASCII graphic characters. Terminals +with %TOSAI set in the TTYOPT variable allow all characters 0-177. +The characters are output at the current graphics cursor position (the +lower left hand corner of the first character's rectangle being placed +there), which is moved as the characters are drawn. The normal +type-out cursor is not relevant and its position is not changed. The +cursor position at which the characters are drawn may be in between +the lines and columns used for normal type-out. The %GOECH operation is +similar to %GODCH but erases the characters specified in it. To clear +out a row of character positions on a bit matrix terminal without +having to respecify the text, a rectangle operation may be used. + + +@Section(Graphics Input) + + The %TRGIN bit in the right half of the TTYSMT variable indicates +that the terminal can supply a graphic input in the form of a cursor +position on request. Sending a %GOGIN operation to the terminal asks to +read the cursor position. It should be followed by an argument +character that will be included in the reply, and will serve to +associate +the reply with the particular request for input that elicited it. The +reply should have the form of a Top-Y character (code 4131), followed +by the reply code character as just described, followed by an absolute +cursor position. Since Top-Y is not normally meaningful as input, +%GOGIN replies can be distinguished reliably from keyboard input. + +Unsolicited graphic input should be sent using a Top-X instead of a +Top-Y, so that the program can distinguish the two. Instead of a reply +code, for which there is no need, the terminal should send an encoding +of the buttons pressed by the user on his input device. For a +three-button mouse, the low two bits contain the number of the button +(1, 2 or 3 from left to right), and the next two bits contain the +number of times the button was clicked. + +@section(Sets) + +The local system may optionally provide the feature of grouping objects +into sets. Then the remote system can blink or move all the objects in a +set without redrawing them all. Sets are not easily implemented on bit matrix +terminals, which should therefore ignore all set operations (except +for a degenerate interpretation in connection with blinking, if that +is implemented). The %TQSET bit in the TTYSMT variable of the +terminal indicates that the terminal implements multiple sets of +objects. + + There are up to 200 different sets, each of which can contain any +number of objects. At any time, one set is selected; objects drawn +become part of that set, and objects erased are removed from it. An +object in another set cannot be erased without selecting that set. +%GOSET is used to select a set. It is followed by a character whose +code is the number of the set to be selected. + +A set can be made temporarily invisible, as a whole, using the %GOINV +operation, without being erased or its contents being forgotten; and it +can then be made instantly visible again with %GOVIS. %GOBNK makes the +whole set blink. %GOCLS erases and forgets all the objects in the +current set. + +Also, a whole set can be moved with %GOMSR or %GOMSA. A set has at all +times a point identified as its "center", and all objects in it are +actually remembered relative to that center, which can be moved +arbitrarily, thus moving all the objects in the set at once. Before +beginning to use a set, therefore, one should "move" its center to some +absolute location. Set center motion can easily cause objects in the +set to move off screen. When this happens, it does not matter what +happens temporarily to those objects, but their "positions" must not be +forgotten, so that undoing the set center motion will restore them to +visibility in their previous positions. + + On a terminal which supports multiple sets, the %GOCLR operation +should empty all sets and mark all sets "visible" (perform a %GOVIS on +each one). So should a %TDCLR SUPDUP command. Thus, any program +which starts by clearing the screen will not have to worry about +initializing the states of all sets. + +Probably only display list systems will support sets. A sufficiently +intelligent bit matrix terminal can provide all the features of a +display list terminal by remembering display lists which are redundant +with the bit matrix, and using them to update the matrix when a %GOMSR +or %GOVIS is done. However, most bit matrix terminals are not +expected to go to such lengths. + +@section(Blinking) + +The %TQBNK bit in TTYSMT indicates that the terminal supports blinking +on the screen. Usually blinking is requested in terms of sets: the +operation %GOBNK means make the selected set blink. All objects in it +already begin blinking, and any new objects drawn in that set also +blink. %GOVIS or %GOINV cancels the effect of a %GOBNK, making the +objects of the set permanently visible or invisible. + +Implementing blinking in terms of sets is convenient, but causes a problem. +It is not very hard for an intelligent bit matrix +terminal to implement blinking for a few objects, if it is told +told in advance, before the objects are drawn. Supporting the use of +sets in general is much harder. To allow bit matrix terminals to +support blinking without supporting sets fully, we provide a convention +for the use of %GOBNK which works with a degenerate implementation of +sets. + +For the remote system, the convention is to do all non-blinking output +in set 0 and all blinking output in set 1, and always send the %GOBNK +@i(before) drawing an object which is to blink. + +For the bit matrix terminal, which offers %TQBNK but not %TQSET, the +convention is that %GOBNK is interpreted as meaning "objects drawn from +now on should blink", and %GOSET is interpreted as meaning "objects +drawn from now on should not blink". The argument of the %GOSET is +ignored, since sets are not implemented. + +When a remote system that is following the convention draws blinking +objects, it will send a %GOSET to set 1 (which has no effect), a %GOBNK +(which enters blinking mode), draw operations for the blinking objects, +and finally a %GOSET to set 0 (which turns off blinking for objects +drawn from now on). If the same sequence of commands is sent to a +terminal which does fully support sets, the normal definitions +of %GOBNK and %GOSET will produce the same behavior. + +Erasing a blinking object should make it disappear, on any terminal +which implements blinking. On bit matrix terminals, blinking @i(must) +be done by XORing, so that the non-blinking background is not destroyed. + + %GOCLS, on a terminal which supports blinking but not sets, +should delete all blinking objects. Then, the convention for deleting +all blinking objects is to select set 1, do a %GOCLS, and reselect set +0. This has the desired effect on all terminals. This definition of +%GOCLS causes no trouble on non-set terminals, since %GOCLS would +otherwise be meaningless to them. + + To make blinking objects stop blinking but remain visible is +possible with a %GOVIS on a terminal which supports sets. It might seem +natural that %GOVIS on non-set terminals should just make all blinking +objects become solid, but this does not work out cleanly. For example, +what would the terminal do if another %GOBNK is output? To be compatible with terminals +that implement sets, the formerly blinking objects would all have to be +remembered. This is an undesirable burden for the simple blinking +terminal, so we do not require it, and the remote system should use %GOVIS +only if sets are actually supported. + +@section(Bit Map Displays: Rectangles, Scan Lines and XOR Mode) + + Bit matrix terminals have their own operations that display list +terminals cannot duplicate. First of all, they have XOR mode, in +which objects drawn cancel existing objects when they overlap. In +this mode, drawing an object and erasing it are identical operations. +All %GOD.. operations become equivalent to the corresponding %GOE..'s. +XOR mode is entered with a %GOXOR and left with a %GOIOR. Display +list terminals that do not implement XOR mode will ignore %GOXOR and +%GOIOR; therefore, programs originating graphics output should +continue to distinguish draw operations from erase operations even in +XOR mode. %TQXOR indicates a terminal which implements XOR mode. XOR +mode, when set, remains set even if graphics mode is left and +re-entered. However, it is wise to re-specify it from time to time, +in case output is lost. + + Bit matrix terminals can also draw solid rectangles. They can +thus implement the operations %GODRR, %GODRA, %GOERR, and %GOERA. A +rectangle is specified by taking the current cursor position to be one +corner, and providing the address of the opposite corner. That can be +done with either a relative address or an absolute one. The %TQREC +bit indicates that the terminal implements rectangle operations. + +Finally, bit matrix terminals can handle data in the form of +scan-lines of bits. The %TRSCN bit in TTYSMT indicates the presence +of this capability. This is done with the operations %GODSC, %GOESC, +%GODRN and %GOERN. The first two draw and erase given actual +sequences of bits as arguments. The last two take run-length-encoded +arguments which say "so many ones, then so many zeros", for data +compression. + +Scan line data for %GODSC and %GOESC is grouped into 16-bit units, and +each 16-bit unit is broken into three argument characters for +transmission. (Three characters are needed since seven bits at most +can be used in each one). The first two argument characters transmit +six bits each, and the third transmits four bits. The most +significant bits of the 16-bit unit are transmitted first; the least +significant four or six bits of the argument character are used. The +end of the scan line data is indicated by 100 (octal) as an argument. + +When drawing, a one bit means turn on the corresponding pixel, and +a zero bit means leave the pixel alone. This is so that pictures output +with scan lines can overstrike with other things. Similarly, when erasing, +clear pixels for one-bits and do not clear them for zero-bits. +In XOR mode, flip pixels for one-bits and leave alone the other pixels. + +Operations %GODRN and %GOERN use run-length-encoded arguments instead of +actual patterns of bits. Each argument character specifies a number of consecutive +one bits or a number of consecutive zero bits. Codes 1 through 77 indicate +a number of zero bits. Codes 101 through 177 indicate a +number of one bits. An argument of zero terminates the %GODRN or %GOERN. +As with the scan operations, a one bit means operate on the corresponding +pixel, and a zero bit means do nothing to it. + +The scan line operations do not usually go well with virtual coordinates; +you cannot escape the fact that you are dealing with the pixel size of +the display when you are controlling individual pixels. + +@section[Using Only Part of the Screen] + + It is sometimes desirable to use part of the screen for picture +and part for text. Then one may wish to clear the picture without +clearing the text. On display list terminals, %GOCLR should do this. +On bit matrix terminals, however, %GOCLR can't tell which bits were +set by graphics and which by text display. For their sake, the %GOLMT +operation is provided. This operation takes two cursor positions as +arguments, specifying a rectangle. It declares that graphics will be +limited to that rectangle, so %GOCLR should clear only that part of +the screen. %GOLMT need not do anything on a terminal which can +remember graphics output as distinct from text output and clear the +former selectively, although it would be a desirable feature to +process it even on those terminals. + + %GOLMT can be used to enable one of several processes which +divide up the screen among themselves to clear only the picture that +it has drawn, on a bit matrix terminal. By using both %GOLMT and +distinct sets, it is possible to deal successfully with almost any +terminal, since bit matrix terminals will implement %GOLMT and display +list terminals almost always implement sets. + + The %TDCLR operation should clear the whole screen, including +graphics output, ignoring the graphics limits. + +@section(Graphics Output by Multiple Processes) + +It may be useful for multiple processes, or independent programs, to +draw on the screen at the same time without interfering with each other. + + If we define "input-stream state" information to be whatever +information which can affect the action of any operation, other than +what is contained in the operation, then each of the several processes +must have its own set of input-stream state variables. + + This is accomplished by providing the %GOPSH operation. The %GOPSH +operation saves all such input-stream information, to be restored when +graphics mode is exited. If the processes can arrange to output +blocks of characters uninterruptibly, they can begin each block with a +%GOPSH followed by operations to initialize the input-stream state +information as they desire. Each block of graphics output should be +ended by a %TDNOP, leaving the terminal in its "normal" state for all +the other processes, and at the same time popping the what the %GOPSH +pushed. + + The input-stream state information consists of: +@itemize[ +The cursor position. + +the state of XOR mode (default is OFF). + +the selected set (default is 0). + +the coordinate unit in use (physical pixels, or virtual) +(default is physical). + +whether output is going to the display screen or to a hardcopy +device (default is to the screen). + +what portion of the screen is in use (see "Using Only Part of the Screen") +(default is all). +] + + Each unit of input-stream status has a default value for the sake +of programs that do not know that the information exists; the +exception is the cursor position, since all programs must know that it +exists. A %TDINI or %TDRST command should set all of the variables to +their default values. + + The state of the current set (whether it is visible, and where +its center is) is not part of the input-stream state information, +since it would be hard to say what it would mean if it were. Besides, +the current set number is part of the input-stream state information, +so different processes can use different sets. The allocation of sets +to processes is the server host's own business. + +@section(Errors in Graphics Operations) + +Errors in graphics operations should be ignored by the local system. +This is because there is no simple way to report an error well enough +to be useful. Since the output and input streams are not +synchronized, the remote system would not be able to tell which of its +operations caused the error. No report is better than a useless report. + +Errors which are not the fault of any individual operation, such as +running out of memory for display lists, should also be ignored as +much as possible. This does @i(not) mean completely ignoring the operations +that cannot be followed; it means following them as much as possible: +moving the cursor, selecting sets, etc. as they specify, so that any +subsequent operations which can be executed are executed as intended. + +@section(Storage of Graphics Operations in Files) + +Since graphics mode operations and their arguments are all in the range 0 through 177, +it is certainly possible to store them in files. However, this is not as useful +as one might think. + +Any program for editing pictures of some sort probably wants to have +a way of storing the pictures in files, but graphics mode operations +are probably not best for the application. This is because the program +presumably works with many kinds of information such as constraints which +are only heuristically deduceable from actual appearance of the picture. +A good representation must explicitly provide a place for this information. +Inclusion of actual graphics operations in a file will be +useful only when the sole purpose of the file is to be displayed. + +@section(Graphics Draw Operations) + +Note: the values of these operations are represented as 8-bit octal +bytes. Arguments to the operations are in lower case inside angle +brackets. @i

represents a cursor position (absolute or relative, +according to the operation description). + +@begin(description) + +%GODLR (code 101) @i

@\ +Draw line relative, from the cursor to @i

. + +%GODPR (code 102) @i

@\ +Draw point relative, at @i

. + +%GODRR (code 103) @i

@\ +Draw rectangle relative, corners at @i

and at the +current cursor position. Only if %TQREC is set in TTYSMT. + +%GODCH (code 104) @i 0@\ +Display the chars of @i starting at the current +graphics cursor position. + +%GODSC (code 105) @i @i@\ +Draw scan bits starting at the current graphics +cursor position. Only if %TRSCN is set in TTYSMT. + +%GODRN (code 106) @i 0@\ +Draw bits determined by @i +starting at the current graphics cursor +position. Only if %TRSCN is set in TTYSMT. + +%GODLA (code 121) @i

Draw line absolute, from the cursor to @i

.@\ +This code does the same thing as %GODLR, except that the cursor +position argument is absolute. + +%GODPA (code 122) @i

@\ +Draw point absolute, at @i

. + +%GODRA (code 123) @i

@\ +Draw rectangle absolute, corners at @i

and at the +current cursor position. Only if %TQREC is set in TTYSMT. + +@end(description) + +@section(Graphics Erase Operations) + +@begin(description) + +%GOELR (code 141) @i

@\ +Erase line relative, from the cursor to @i

. + +%GOEPR (code 142) @i

@\ +Erase point relative, at @i

. + +%GOERR (code 143) @i

@\ +Erase rectangle relative, corners at @i

and at the +current cursor position. Only if %TQREC is set in TTYSMT. + +%GOECH (code 144) @i 0@\ +Erase the chars of @i starting at the current +graphics cursor position. + +%GOESC (code 145) @i @i@\ +Erase scan bits starting at the current graphics +cursor position. Only if %TRSCN is set in TTYSMT. + +%GOERN (code 146) @i 0@\ +Erase bits determined by @i +starting at the current graphics cursor +position. Only if %TRSCN is set in TTYSMT. + +%GOELA (code 161) @i

@\ +Erase line absolute, from the cursor to @i

. + +%GOEPA (code 162) @i

@\ +Erase point absolute, at @i

. + +%GOERA (code 163) @i

@\ +Erase rectangle absolute, corners at @i

and at the +current cursor position. Only if %TQREC is set in TTYSMT. +@end(description) + +@section(Graphics Control Operations) + +@begin(description) +%GOMVR (code 001) @i

@\ +Move cursor to point @i

+ +%GOMVA (code 021) @i

@\ +Move cursor to point @i

, absolute address. + +%GOXOR (code 002)@\ +Turn on XOR mode. Only if %TQXOR is set in TTYSMT. + +%GOIOR (code 022)@\ +Turn off XOR mode. Only if %TQXOR is set in TTYSMT. + +%GOSET (code 003) @i@\ +Select set. @i is a 1-character set number, 0 - 177. Only if %TQSET +is set in TTYSMT, except for a degenerate interpretation when %TQBNK is +set and %TQSET is not. + +%GOMSR (code 004) @i

@\ +Move set origin to @i

. Only if %TQSET is set in TTYSMT. + +%GOMSA (code 024) @i

@\ +Move set origin to @i

, absolute address. Only if %TQSET is set in TTYSMT. + +%GOINV (code 006)@\ +Make current set invisible. Only if %TQSET is set in TTYSMT. + +%GOVIS (code 026)@\ +Make current set visible. Only if %TQSET is set in TTYSMT. + +%GOBNK (code 007)@\ +Make current set blink. Canceled by %GOINV or %GOVIS. Only if %TQBNK +is set in TTYSMT. + +%GOCLR (code 010)@\ +Erase the graphics portion of the screen. If possible, erase all +graphics output but not normal output. + +%GOCLS (code 030)@\ +Erase entire current set. Only if %TQSET is set in TTYSMT, except for a +degenerate interpretation if %TQBNK is set and %TQSET is not. + +%GOPSH (code 011)@\ +Push all input-stream status information, to be +restored when graphics mode is exited. + +%GOVIR (code 012)@\ +Start using virtual coordinates. Only if %TQVIR is set in TTYSMT. + +%GOPHY (code 032)@\ +Resume giving coordinates in units of pixels. + +%GOHRD (code 013) @i@\ +Divert output to output subdevice @i. +@i=0 reselects the main display screen. +Only if %TQGHC is set in TTYSMT. + +%GOGIN (code 014) @i@\ +Request graphics input (mouse, tablet, etc). +@i is the reply code to include in the answer. +Only if %TQGIN is set in TTYSMT. + +%GOLMT (code 015) @i @i@\ +Limits graphics to a subrectangle of the screen. +%GOCLR will clear only that area. The cursor positions are both +absolute! + +@end(description) + +@Unnumbered(Local Editing Protocol) + +The purpose of the Local Editing Protocol is to improve the response +time in running a display text editor on the remote +system through SUPDUP. It enables the local computer to +perform most of the user's editing commands, with the locus of +editing moving between the local and remote systems in a manner +invisible to the user except for speed of response. + +Bits in the TTYSMT word tell the remote system that the local system +supports one or both of these subprotocols of SUPDUP. It is up to the +remote system to use them or not. + +Any local editing protocol must accomplish these things: + +@enumerate[ +The representation used for the remote editor's text display output +must contain sufficient information for the local system to deduce the +text being edited, at least enough to implement the desired editing +commands properly. + +The remote system must be able to tell the local system when to do +local editing. This is because the remote system is not always +running the text editor, and the editor may have modes in which +characters are not interpreted in the usual way. If the protocol is +to work with a variety of editors, the editor must be able to tell the +local system what the definition is for each editing command, and +which ones cannot be handled locally at all. Extensible editors +require the ability to tell the local system a new definition for any +character at any time. + +The local system must be able to verify for certain that all the input +it has sent to the remote system has been processed, and all the +resulting output has been received by the local system. We +call this process "synchronization". To attempt local editing if this +condition is not met would cause timing errors and paradoxical +results. + +The local system must be able to tell the remote system in some +fashion about any editing that has been performed locally. + +Local editing must cease whenever an unpredictable event such as a +message from another user causes output which the local system will +misunderstand. +] + +Each component of the Local Editing Protocol is present to satisfy one +of the design requirements listed above. So the description of the +protocol is broken up by design requirement. +Each requirement is the subject of one section below. + +@Subsection[Making Output Comprehensible for Editing] + +The primary purpose of the SUPDUP protocol is to represent +display terminal I/O in a hardware-independent fashion. A few new +%TD commands plus some conventions as to how the existing %TD commands +are used by remote editors are enough to allow the contents of the +edited text to be deduced. + +The local system must not only obey these commands but also keep a +record of the characters on the screen suitable for executing the +user's editing commands. This basically consists of keeping an +up-to-date matrix which describes what character is at each screen +position. However, it is not as simple as that. The problem cases are: + +@enumerate[ +Space characters and tab characters in the text being edited must be +distinguished. Although a tab character may look the same as a +certain number of space characters at one particular time, it does not +behave like that number of space characters if text is inserted or +deleted to the left of it. + +Control characters may be output in a fashion indistinguishable from +some sequence of printing characters. For example, EMACS displays the +ASCII character control-A as "^A". +Editing commands which operate on single characters may be confused by +this. + +One line on the screen may not correspond to one line of text being +edited. EMACS represents a long line of text using several screen +lines. Some other editors allow text to be invisible before the left +margin or after the right margin. + +Not all of the screen space is used for displaying the text being +edited. Some parts of the screen may be reserved for such things as +status information, command echoing, or other editing windows. The +local system must avoid moving the cursor into them or editing them as +if they were text. + +Space characters at the end of a line in the text being edited must be +distinguished from blank space following the displayed line, since some +editors (including EMACS) distinguish them. Both the Forward Character +and End of Line commands need this information. +] + +For each of these problem cases, the Local Editing Protocol has an +editor-independent solution: + +@enumerate[ + +We enable the local system to distinguish spaces from tabs in the text +being edited by defining a output command Space-for-Tab (%TDTSP). It is +used by the remote editor to represent the spaces which make up the +representation of a tab character. The local system displays it just +like a space character, but records it differently. + +An editor-independent solution to the problem of ambiguous display of +control characters is a new output command, %TDMLT @i +@i, which says that the next @i screen positions are part of the +display of one character of text, with code @i. Using this, EMACS +outputs a control-A using five characters: %TDMLT 002 ^A ^ +A. The local system must record this, keeping track of which positions +are grouped together to represent one text character. The record should +be cleared when the positions involved are erased. + +Text lines that run over the ends of screen lines are said to be +@i(continued). To deal with continued lines, we define two new output +commands, %TDCTB and %TDCTE These tell the local system that the +beginning or end of the screen line, respectively, is not really the +beginning or end of a line in the text being edited. For EMACS, %TDCTE +on one line would always accompany %TDCTB on the next, but this might +not be appropriate for other editors. Both of these commands must set +bits that accompany the lines when they are moved up or down on the +screen. The %TDCTE bit should be cleared by anything which erases the +end of the line, and by %TDDCP within the line. The %TDCTB bit should +be cleared by anything which erases the entire line. EMACS always +outputs a %TDCTB for the first line on the screen, since EMACS does not +attempt to think about the text before what appears on that line. + +Any parts of the screen that are being used for things other than the +text being edited can be marked off limits to local editing by setting +the editing margins. Inside each edge of the screen there is an editing +margin. The margin is defined by a width parameter is normally zero, +but if it is set nonzero by the remote system, then that many columns or +rows of character positions just inside the edge are made part of the +margin. By setting the margins, local editing can be restricted to any +rectangle on the screen. The margins are set by means of a special +kind of %TDEDF (see below). + +@multiple[ +Space characters at the end of a line are distinguished by means of +conventions for the use of the erasing commands %TDEOL, %TDCLR and +%TDDLF. The convention is that %TDDLF is used +only to clear text in the middle of a line, whereas the others imply +that all the text on the line (or all the text past the point of erasure) +will be reprinted. Although the area of screen erased by +%TDEOL or %TDCLR becomes blank, the +screen-record +matrix elements for those areas is filled with a special character, +distinct from the space character and from all graphic characters. +Character code 200 will serve for this. Spaces in the text are output +by the editor as actual spaces and are recorded as such in the +screen-record matrix. Blanks created in the middle of the line by +%TDICP are recorded as space characters since character insertion +is done only within the text of the line. Blanks created at the end of +the line by %TDDCP are recorded as character 200 since they are +probably past the end of the text (or else the text line extends past +this screen line, which will be reported with %TDCTE). + +If the screen record and the editor obey the above conventions, the +end of the text on the line is after the last character on the line +which is not 200. (Note that this can only be relied upon to be the end +of a line of text if %TDCTE has not been done on this screen line). +]] + +@Subsection[Defining the Editing Commands] + +When a remote editor requests local editing, it must tell the local +system what editing function belongs to each character the user can +type. In SUPDUP local editing, %TDEDF is used for this. If character +meanings change during editing, the editor must tell the local system +about the changes also. In most display editors, text is inserted by +typing the text, so we regard printing characters as editing commands +which are usually defined to insert themselves. + +A %TDEDF command usually specifies the editing +meaning of one user input character. The first time the remote editor +enables local editing, it must first specify the definitions of all user +input characters with %TDEDF commands. On subsequent occasions, +%TDEDF commands need only be used for characters whose meanings +have changed. + +In addition to the definitions of user input characters, the local +system needs to know certain other parameters which affect what editing +commands do. These are the word syntax table, the fill column, and the +insertion mode. + +Commands which operate on words must know which text characters to treat +as part of a word. This can be changed by activities on the remote +system (such as, switching to editing a different file written in a +different language). A special form of %TDEDF command (code 31) is used to +specify the word syntax bit for one text character. See below. + +EMACS has an optional mode in which lines are broken automatically, at +spaces, when they get too long. In such a feature, certain +characters@footnote(In EMACS, the Space character) which are normally +self-inserting may break the line if the line is too long. Such +characters cannot simply be defined as self-inserting. Instead, they +should be defined as @i[self-inserting before the fill column] (code +40). The fill column is a parameter whose purpose is to specify where +on the line these characters should cease to be handled locally. A +special form of %TDEDF (code 41) sets the value of the fill column. + +Since many editors, including EMACS, have modes which ordinary +printing characters either push aside or replace existing text, the +Local Editing Protocol defines an @i[insertion mode] parameter to +control this. If the insertion mode parameter is 1, ordinary printing +characters insert. If the insertion mode parameter is 2, they +overwrite existing text. If the parameter is 0, all ordinary printing +characters become unhandleable. Note that which characters are +"ordinary printing characters" is controlled by the assigned function +codes. + +A special form of %TDEDF command (code 32) is used to set the insertion mode +parameter. To switch between insert and overwrite modes, it is +sufficient to change this parameter; it is not necessary to change the +definitions of all the printing characters. Also, simple commands which +change the insertion mode can be handled locally, though we have not +actually defined any such function. + +Another special form of %TDEDF (code 34) is used to set the editing +margins, which say what part of the screen is used for local editing. + +Another special form of %TDEDF command (code 33) initializes the +definitions of all user input characters, all the word syntax table +bits, the fill column and the insertion mode to a standard state. This +state is not precisely right for any editor, but it gets most characters +right for just about all editors. It sets up all ASCII printing +characters to insert themselves; aside from them, the number of commands +handled locally for any given editor is small. When an editor is first +transmitting its command definitions to the local system, it can greatly +reduce the number of %TDEDF commands needed by first using code 33 to +initialize all characters and then fixing up those command definitions +and parameters whose standard initial states are not right. + +Each %TDEDF command contains a user input character and a function +code. The function codes are established by the Local Editing Protocol +specifically for use in %TDEDF. Normally the function code +specifies the editing definition of the associated user input +character. A few function codes indicate the special forms of +%TDEDF command which set parameters or initialize everything. + +@Paragraph[%TDEDF Function Codes] + +Here is a list of function codes (all in octal) and their meanings, +plus implementation directions. + +@begin[description] +0@\This character should not be handled locally. +Either it is undefined, or its definition in the remote editor has +no local equivalent. + +1@\Move forward one character. Do not handle the command locally at +the end of the text on a line. + +2@\Move backward one character. Do not handle the command locally at +the beginning of a line. + +3@\Delete the following character. Do not handle the command locally +at the end of the text on a line, or on a line which is continued at the end. + +4@\Delete the previous character. Do not handle the command locally at +the beginning of a line, or on a line which is continued at the end. + +5@\Move backward one character. Treat a tab as if it were made of +spaces. Do not handle the command locally at the beginning of a line. + +6@\Delete the previous character. Treat a tab as if it were made of +spaces. Do not handle the command locally at the beginning of a line, +or on a line which is continued at the end. + +7@\This is the usual function code for printing characters. The +insertion mode parameter says what characters assigned this function +code ought to do. They can insert (push the following text over), or +replace (enter the text in place of the following character). Or they +may be not handled at all. See function code 32, which sets the +insertion mode. When the current mode is "replace", if the following +character may occupy more than one position, the command should not be +handled locally. When the insertion mode is "insert", the command +should not be handled locally on a line continued at the end. + +10@\Move cursor up vertically. Do not handle the command locally if +the cursor would end up in the middle of a tab character, or past the +end of the line, or if either the line which the cursor starts on or the +previous line is continued at the beginning. + +11@\Similar, but move down instead of up. Do not handle locally if +either the line the cursor starts on, or the following line, is continued at +the beginning. + +12@\Like code 10, but treat tabs just like so many spaces. + +13@\Like code 11, but move down. + +14@\Move cursor to beginning of previous line. Must not be handled +locally if either the current line or the previous line is continued at the beginning. + +15@\Move cursor to beginning of next line. Must not be handled +locally if next line has been marked as continued at the beginning. + +16@\Insert a line-break at the cursor and move the cursor after it. +Should not be handled locally if the cursor horizontal position is +greater than or equal to the fill column (plus the left editing margin). + +17@\Insert a line-break at the cursor but do not move the cursor. +Does not pay attention to the fill column either. + +20@\Move cursor to beginning of current line. Must not be handled +locally if this line has been marked as continued at the beginning. + +21@\Move cursor to end of current line. Must not be handled +locally if this line has been marked as continued at the end. + +22@\Use the definition of another character whose code is determined +from this character. The details and purpose of this function are +explained in the section on @ref(caseindirect). + +23@\Move cursor to the end of the following word. Do not handle +locally if the word appears to end at the end of the line and the line +is marked as continued at the end. + +24@\Move cursor to the beginning of the previous word. Do not handle +locally if the word appears to begin at the beginning of the line and +the line is marked as continued at the beginning. + +25@\Delete from cursor to the end of the following word. +Do not handle locally on a line marked as continued at the end. + +26@\Delete from cursor to the beginning of the previous word. Do not +handle locally on a line marked as continued at the end, or when code +24 would not be handled locally. + +27@\Specify a digit of a repeat count. The low seven bits of the +command character with this definition should be an ASCII digit. This +digit should be accumulated into a repeat count for the next command. +The next character which is not part of the repeat count uses the +repeat count. The argument-specifying characters cannot be handled +locally unless the command which uses the argument is also handled +locally. So those characters must be saved and not transmitted until +the following command has been read and the decision on handling it +locally has been made. If it is impossible to handle all the +specified repetitions of the command locally, the command should not +be handled locally at all. + +30@\Introduces digits which make up an argument. The following +characters, as long as they are digits (or a leading minus sign), +should be saved and used as a repeat count for the first character +which is not a digit or minus sign. + +31@\This function code does not actually define the accompanying +character. Instead, it specifies the word syntax table bit for one +ASCII character. As arguments, it requires an ASCII character and a +syntax bit. See the section on SUPDUP +output, under %TDEDF, for further information. + +32@\This function code is used to specify the insertion mode +parameter. The accompanying "character" should have numeric code 0, 1 +or 2. This "character" is the new setting of the parameter. 0 means +that the ordinary printing characters, those characters with function +code 7, should not be handled locally. 1 means that they should +insert, and 2 means that they should replace existing text. The +definition of character code 0, 1, or 2 is not changed. + +33@\This function code ignores the accompanying character and +initializes the definitions of all command characters, as well as the +word syntax table and insertion mode. See the section on SUPDUP +output, under %TDEDF, for further information. + +34@\Set margin. This function code specifies one of the editing +margins. See the section on SUPDUP output, under %TDEDF, for further +information. + +35@\Move cursor up vertically, ignoring continuation. Like code 10, +but handle locally regardless of whether lines are continued. + +36@\Move cursor down vertically, ignoring continuations. Like code 35 +but move down. + +40@\Self-insert, within the fill column. Interpreted like code 7 +(self-insert), except do not handle locally if the current cursor +column is greater than or equal to the fill column parameter (plus the +left editing margin). + +41@\Set fill column. This function code specifies the value of the +fill column parameter. The numeric value of the accompanying +"character" is the new value of the parameter. If the fill column +parameter is zero, the fill column feature is inactive. Otherwise, +certain function codes are not handled when the cursor horizontal +position is greater than the fill column (plus the current left +editing margin). Function codes affected are 16, 40 and 42. + +42@\Insert line-break, moving over it, except that if the cursor is at +the end of a line which is not continued, and a blank line follows, move +the cursor onto the blank line. Should not be handled locally if the +current cursor column is greater than or equal to the fill column +parameter (plus the left editing margin). + +43@\Scroll up. Scrolls region of editing up a number of lines +specified by an accumulated numeric argument. Do not handle locally +if no numeric argument accumulated locally. Local handling is +possible only if the local system knows the contents of lines off +screen due to use of the line saving protocol or anticipatory output. + +44@\Scroll down. Similar to 43 but scrolls down instead of up. + +@end[description] + +All insertion and deletion functions should take special notice of any +tab characters (output with Space-for-Tab) on the line after the cursor. +Unless the local system wishes to make assumptions about the tab stops in +use by the remote system, no insertion or deletion may be done before a +tab. In such a situation, insertion and deletion commands should not be +handled locally. + +No local system is required to handle all the function codes. +For example, our preliminary implementation does not handle the +vertical motion, insertion of line breaks, or arguments. Any function +code which the local system prefers not to handle can be treated as +code 0; the characters with that definition are simply not handled +locally. The local system is also free to fail to handle any +command character locally for any reason at any time. + +Some functions are deliberately left undefined in particular unusual +cases, even though several obvious remote definitions could easily be +simulated, so that they can be used by a wider variety of editors. For +example, editors differ in what they would do with a command to move +forward one character at the end of the text on a line. EMACS would +move to the beginning of the next line. But Z would move into the space +after the line's text. Since function code 1 is defined in this case +not to be handled locally, either EMACS or Z could use it. + +@subsection[Synchronization] + +The local system sees no inherent synchronization between the channels +to and from the remote system. They operate independently with their +own buffers. + +When the local system receives an input character from the user which +it cannot handle, either because its definition is not handleable or +because local editing is not going on at the moment, it sends this +character to the remote system to be handled. After processing the +character, the remote system may decide to permit local editing. It +must send a command to the local system to do so. By the time the +local system receives this command, it may already have received and +sent ahead several more input characters. In this case, the command +to permit local editing would be obsolete information, and obeying it +would lead to incorrect display. + +The Local Editing Protocol contains a synchronization mechanism +designed to prevent such misbehavior. It enables the local system, +when it receives a command to begin local editing, to verify that +the remote system and the communication channels are quiescent. + +Before the remote editor can request local editing, it must ask for +synchronization. This is done by sending the output command +%TDECO (Prepare-for-Local-Editing). After receiving this, the local system +lays the groundwork for synchronization by sending a resynchronize +command to the remote system. This is a two-character sequence whose +purpose is to mark a certain point in the input stream. By counting +characters, later points in the input stream can also be marked, +without need for constant resynchronize commands. + +The resynchronize command begins with a special code which was +previously meaningless in the SUPDUP input language. The second +character of the sequence is a identifier which the remote system will +use to distinguish one resynchronize command from another. It is best +to use 40 the first time, and then increment the identifier from one +resynchronize to the next, just to avoid repeating the identifier +frequently. + +When the remote editor actually wishes to permit local editing, after +sending %TDEDF commands as necessary, it sends a %TDSYN (Do-Local-Editing) +command, also known as a resynch reply. This command is followed by +two argument bytes. The first one repeats the identifier specified in the +last resynchronize command received, and the second is simply the +number of input characters received at the remote system since that +resynchronize command. + +When the local system sees the resynch reply, it compares the +identifier with that of the last resynch that @i[it] sent, and +compares the character count with the number of characters @i[it] has +sent since the last resynch. If both match, then all pipelines are +empty; the remote system has acknowledged processing all the +characters that were sent to it. Local editing may be done. + +If the resynch identifier received matches the last one sent but the +character counts do not, then more input characters are in transit +from the local system to the remote system, and had not been processed +remotely when the %TDSYN was sent. So local editing cannot begin. + +If the identifiers fail to match, it could be that the remote system +is confused. This could be because the user is switching between two +editors on the remote system. After each switch, the newly resumed +editor will be confused in this way. It could also be that the remote +editor sent a resynch reply for the previous resynch, while the last +one was on its way. In either case, the proper response for the local +system is to send another resynch. It should wait until the user +types another input character, but send the resynch before the input +character. This avoids any chance that a resynch itself will prevent +local editing by making the pipelines active when they would have been +quiescent. + +The first %TDSYN after a %TDECO is +usually preceded by many %TDEDF commands to initialize all the +editing commands. Later %TDSYN commands are preceded by +%TDEDFs only for commands whose meanings have changed. + +Since the character count in a %TDSYN cannot be larger than +177, a new resynchronize should be sent by the local system every so +often as long as resynchronization is going on. We recommend every +140 characters. Once again, the resynch should be sent when the next +input character is in hand and ready to be sent. If the remote system +sees more than 177 input characters without a resynchronize, it should +send another %TDECO. + +Once synchronization has been verified and local editing begins, it +can continue until the user types one character that cannot be +handled locally. Once that character has been transmitted, +local editing is not allowed until the next valid %TDSYN. + +@subsection[Reporting Results of Local Editing] + +When the local system has done local editing, it must eventually report to the +remote system what it has done, so that the changes can be made +permanent, and so that following commands handled remotely can have +the proper initial conditions. + +In the Local Editing Protocol, the local editing is reported by +transmitting the editing commands themselves, preceded by a special +marker which identifies them to the remote system as locally handled. +The special marker two characters long; it consists of the extended +ASCII character 4105 (4000 plus E) followed by a byte containing the +number of locally handled editing characters that follow. Thus, a +locally handled sequence X Z Control-B Y would be sent as 4105 4 130 132 +302 131. + +When the remote editor receives the locally-handled commands, it +executes them as usual, but it does not actually update the display. +It only @i[pretends to itself] that it did. It updates all its tables +of what is on the screen, just as it would if it were updating the +display, but it does not output anything. This brings the remote +editor's screen-records into agreement with the actual screen contents +resulting from the local editing. + +Local systems are recommended to output all accumulated locally +handled commands every few seconds if there is no reason to do +otherwise. Sending a few seconds worth of input commands all at +once causes the remote editor to run for fewer long periods rather than +many short periods. This can greatly reduce system overhead in +timesharing systems on which process-switching is expensive. + +@subsection[Unexpected Output From Remote System] + +If output is received from the remote system while local editing is +going on, the local system should stop doing local editing, and should +not send any more resynchs until another %TDECO is received. If the +remote system generates output that the text editor does not know about, +it should notify the text editor to send another %TDECO. + +The remote system can send the command %TDNLE (Stop-Local-Editing) as a +clean way of stopping local editing. It has the same effect. + +@Unnumbered[The Line Saving Protocol] + +The Line Saving Protocol allows the remote editor to tell the +local terminal to save a copy of some displayed text, and later refer +to the copy to put that text back on the screen without having to +transmit it again. + +The Line Saving Protocol reduces the amount of output required in such +situations by allowing text once displayed to be saved, and restored +whenever the same text is to be displayed again. Moving to a part of +the file which had been displayed at an earlier time no longer requires +transmitting the text again. + +@Section[The Design of the Line Saving Protocol] + +The basic operations provided by the Line Saving Protocol are those of +saving and restoring the contents of individual lines on the screen. + +A line on the screen is saved for later use by giving it a label. The +line remains unchanged on the screen by this operation, but a copy of +the contents are saved. At a later time, the saved contents can be +brought back onto the screen, on the same line or another one, by +referring to the same label. + +A label number is 14 bits wide (transmitted as two bytes of 7 bits, +low bits first), but local systems are not required to be able to +handle 2@+[14] different labels. The %TRLSV field in the TTYSMT +variable tells the remote system approximately how many different +labels the local system can remember. The remote system should not +try to use a larger label number. The local system ought to be able +to remember approximately that number of labels under normal +circumstances, but it is permitted to discard any label at any time +(because of a shortage of memory, perhaps). + +Lines are saved with the command %TDSVL (Save-Lines). It takes three +bytes of arguments: one for the number of lines to save, and two for +the label. Several +consecutive lines are saved under consecutive labels, starting with +the line the cursor is on and the specified label, then moving downward +and incrementing the label number. + +To restore lines, the remote system should send a %TDRSL (Restore-Lines) +command. %TDRSL takes arguments just like %TDSVL, but it copies the +saved text belonging to the labels back onto the screen. The meanings +of the labels are forgotten when the labels are restored. + +Because some editors can use for text display a region of the screen +which does not extend to the left and right margins, there is another +command to specify which range of columns should be saved and restored. +%TDSSR (Set-Saving-Range) @i @i specifies that contents of lines +should +be saved and restored from column @i (inclusive) to column @i +(exclusive). Zero-origin indexing is used. + +Line contents should be saved and restored by actual copying; or by some +other technique with equivalent results. + +If the local system is asked to restore a label for which there is no +record, it should send to the remote system the sequence 4124 (4000 plus +T) followed by the number of lines (one byte) and starting label (two +bytes). This is called a Label-Failure sequence. The remote system, on +receiving this, should record that those labels are no longer available +and reoutput the contents of those lines from scratch. In order to +implement this, the remote system must remember which lines it attempted +to restore from which labels. + +@section[Interaction between Local Editing and Line Saving] + +Some local editing commands can push lines off the screen. +If Line Saving is in use as well, the remote system can ask for such +lines to be saved with labels in case they are useful later. + +The command %TDSLL (Set-Local-Label) @i sets the label to be +used for the next line to be pushed off the screen by local editing. +Successive such lines decrement this parameter by 1. If several lines +are pushed off the screen at once, they are processed lowest first. +This tends to cause several consecutive lines which have been pushed off +the screen to have consecutive labels, whether they were pushed off +together or individually. That way, they can be restored with a single +%TDRSL command. + +Because the remote editor is always expected to know how locally handled +commands have updated the display, it can always tell when a line has +locally been given a label. + +@Bigsection[Anticipatory Output] + +The remote system can use the time when the user is idle to send and +label lines which are not needed on the screen now but might be useful +later. Such @i(anticipatory output) can be brought onto the screen by a +%TDRSL command from the remote system or by a locally-handled scrolling +command. + +To begin a line of anticipatory output, the remote editor sends a %TDMCI +(Move-Cursor-Invisible) command, which is followed by a 14-bit signed +number called the logical vertical position (transmitted as two 7-bit +bytes, low bits first). The value of this number indicates the +relationship between this line of output and the text on the screen, for +the sake of local editing. After the output is done, the contents can +be saved under a label, if the local system supports line saving. In +any case, text output after the cursor has been moved with a %TDMCI +should not appear on the screen. The terminal's actual cursor should +remain where it was before the %TDMCI. + +When local editing is in progress, unexpected output which moves the +cursor to an invisible line, or outputs characters to such a line, +should not terminate local editing. Only unexpected output to the +actual screen, or moving the cursor onto the screen, should do that. +Output which is actually unrelated to the editor ought to start with a +%TDMV0 and will be detected by this test. + +The logical vertical position specifies the position of this line on +an infinitely long screen which contains the actual lines of locally +editable text at their actual positions. For example, if the current +editing margins specify that lines 2 through 20 are used for local +editing, then a line output at logical vertical position -3 contains +what would appear five lines above the first displayed line of edited +text, and a command to scroll down five lines would bring it onto the +screen at line 2. A line might be displayed at logical vertical +position 1; it would be invisible, but a command to scroll down one +line would make it visible on line 2. + +If the local system does not support local editing, the value used for +the logical vertical position is immaterial; the only purpose of +outputting the line is to save it under a label. In this case, the +local system is not required to save multiple invisible lines +according to logical vertical position. It may keep only the last one +output. So each transmitted line should be saved under a label as +soon as it is finished. + +The remote operating system and the network are likely to have a large +buffering capacity for output. Since anticipatory output is used +primarily on slow connections, the remote editor could easily produce +and buffer in a second an quantity of anticipatory output which will take many +seconds to transmit. While the backlog lasts, the user would obtain no +service for his explicit commands, except those handled locally. +To prevent this, the remote editor ought to send anticipatory output +in batches of no more than two or three lines' worth, and send these +batches at an average rate less than the expected speed of the bottleneck of the +connection. In between batches, it should check for input. + +The %TRANT field of the TTYSMT word tells the remote system +approximately how many lines of anticipatory output the local system can +support for local editing use. The remote system should use this as a +guide. It is free to send whatever it wants, and the local system is +free to decide what to keep and what to throw away. + +@Unnumbered[References] + +@description[ +Arpanet@\"Arpanet Protocol Handbook", Network Information Center, SRI +International. + +Chaosnet@\Dave Moon, "Chaosnet", MIT Artificial Intelligence Lab memo +628, June 1981. + +Echo Negotiation@\Bernard S. Greenberg +"Multics Emacs: an Experiment in Computer Interaction" +in Proceedings, Fourth International Honeywell Software +Conference, Honeywell, Inc., March, 1980, Bloomington, Minn. + +EMACS@\Richard M. Stallman, "EMACS, the Extensible, CUstomizable, +Self-Documenting Display Editor", Artificial Intelligence Lab memo +519a, April 1981. + +TCP@\Jon Postel, "DOD Standard Transmission Control Protocol", +USC/Information Sciences Institute, IEN-129, RFC 761, NTIS ADA082609, +January 1980. Appears in: Computer Communication Review, Special +Interest Group on Data Communication, ACM, V.10, N.4, October 1980. + +Z@\Steven R. Wood, "Z, the 95% Program Editor", in the proceedings of the SIGPLAN +conference on text manipulation, June 1981. +] + + diff --git a/contrib/supdup/supdupd.c b/contrib/supdup/supdupd.c new file mode 100644 index 0000000..35a9fa3 --- /dev/null +++ b/contrib/supdup/supdupd.c @@ -0,0 +1,1487 @@ +/* SUPDUP Server + * + * Written Jan. 84 by David Bridgham. The organization and some of + * the code was taken from the telnet server written by Berkeley for 4.2. + */ + +/* Hacked by Mly to clarify ITS ITP July 1987 + * Hacked by Mly 29-Aug-87 to nuke stupid auto_right_margin lossage + * Hacked by Mly 2-Sep-87 to send params as "4;" and "146;" rather than + * "\004" and "\222" to avoid stupid un*x 8-bit-and-control-d non-transparency + * Hacked by wesommer@athena.mit.edu 25-Jan-88 to use winning 4.3BSD + * -p flag to /bin/login and to do TIOCSWINSZ stuff. + * #ifdef TTYLOC around ttyloc-hacking parts + */ + +/* The magic number #o176 which appears in this file is the difference + * between the real Supdup TDxxx codes and the kludge codes which appear + * in the termcap/terminfo descriptions (which are needed because bloody + * un*x deals incompetently with chars with the #o200 bit on + * (as well as with #o004. Cretins.) + * Thus, for example, we have %TDMV0 = #o217, with "cm=\177\021%d;%d;:" + * in the termcap entry; (- #o 217 #o021) => #o176 + */ + +/* #define TERMINFO 1 */ /* Define if want terminfo support. */ + /* there should be a TERMCAP too */ + +#include +#include +#include +#include + +#include + +/* #include */ +#include "supdup.h" + +#include +#include +#include +#include +#include + +#ifdef TERMINFO +# include +# undef CUR +# define CUR +#endif /* TERMINFO */ + +#ifndef BANNER +#define BANNER "MIT Artificial Intelligence Laboratory 4.2 BSD UNIX (%s)\207%s" +#endif + +#ifndef SBANNER +#define SBANNER "%s SUPDUP from %s" +#endif + +/* * I/O data buffers, pointers, and counters. */ +unsigned char ptyibuf[BUFSIZ], *ptyip = ptyibuf; +unsigned char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf; +unsigned char netibuf[BUFSIZ], *netip = netibuf; +unsigned char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; +int pcc, ncc; + +/* Filedesc for stream connected to local un*x pty. */ +int pty; +/* Filedesc for stream connected to user (via internet) */ +int net; +struct sockaddr_in sin = { AF_INET }; +int reapchild (); + +char pty_name[] = "/dev/ptyq0"; +#ifdef TTYLOC +char ttyloc[64]; +#endif /* TTYLOC */ + +extern char **environ; +extern int errno; + + +/* Current cursor position */ +int currcol, currline; + +#ifndef TERMINFO /* terminfo defines these itself */ +/* Number of columns, lines of virtual terminal */ +int columns, lines; +#endif + + +#ifndef DEBUG +#define DPRINTF(a, b, c) {} +#else /* DEBUG */ + +#define DPRINTF(a, b, c) \ + if (debug_output) \ + { fprintf (debug_output, (a), (b), (c)); fflush (debug_output); } + +FILE *debug_output = 0; +void +open_debug_output () +{ + debug_output = fopen ("/supdupd.debug", "w"); + if (debug_output < 0) + { + fprintf (stderr, "Couldn't open \"/supdupd.debug\"\n"); + debug_output = 0; + } + + DPRINTF ("Starting up supdupd...\n",0,0); +} +#endif /* DEBUG */ + +#if 0 +/* this routine is used for debugging only */ +echo_char (c) + unsigned char c; +{ + static int count = 0; + + if (count++ > 16) + { + printf ("\n"); + count = 0; + } + if (c >= '\177') printf ("\\%o ", c); + else if (c < '\041') printf ("\\%o ", c); + else printf ("%c ", c); + fflush (stdout); +} +#endif /* 0 */ + + +#ifdef DAEMON +main (argc, argv) + int argc; + char *argv[]; +{ + int s, pid, options; + struct servent *sp; + +#ifdef DEBUG + open_debug_output (); +#endif /* DEBUG */ + + sp = getservbyname ("supdup", "tcp"); + if (sp == 0) + { + fprintf (stderr, "supdupd: tcp/supdup: unknown service\n"); + exit (1); + } + sin.sin_port = sp->s_port; + argc--, argv++; + if (argc > 0 && !strcmp (*argv, "-d")) + { + options |= SO_DEBUG; + argc--, argv++; + } + if (argc > 0) + { + sin.sin_port = atoi (*argv); + if (sin.sin_port <= 0) + { + fprintf (stderr, "supdupd: %s: bad port #\n", *argv); + exit (1); + } + sin.sin_port = htons ((u_short)sin.sin_port); + } +#ifndef DEBUG + if (fork ()) + exit (0); + for (s = 0; s < 10; s++) + (void) close (s); + (void) open ("/", 0); + (void) dup2 (0, 1); + (void) dup2 (0, 2); + { + int tt = open ("/dev/tty", 2); + if (tt > 0) + { + ioctl (tt, TIOCNOTTY, 0); + close (tt); + } + } +#endif /* DEBUG */ +again: + s = socket (AF_INET, SOCK_STREAM, 0, 0); + if (s < 0) + { + perror ("supdupd: socket");; + sleep (5); + goto again; + } + if (options & SO_DEBUG) + if (setsockopt (s, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) + perror ("telnetd: setsockopt (SO_DEBUG)"); + if (setsockopt (s, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) + perror ("supdupd: setsockopt (SO_KEEPALIVE)"); + while (bind (s, (caddr_t) &sin, sizeof (sin), 0) < 0) + { + perror ("supdupd: bind"); + sleep (5); + } + signal (SIGCHLD, reapchild); + listen (s, 10); + for (;;) + { + struct sockaddr_in from; + int s2, fromlen = sizeof (from); + + s2 = accept (s, (caddr_t)&from, &fromlen); + if (s2 < 0) + { + if (errno == EINTR) + continue; + perror ("supdupd: accept"); + sleep (1); + continue; + } + if ((pid = fork ()) < 0) + printf ("Out of processes\n"); + else if (pid == 0) + { + signal (SIGCHLD, SIG_DFL); + doit (s2, &from); + } + close (s2); + } + /*NOTREACHED*/ +} + +#else /* not DAEMON */ +main (argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in from; + int fromlen; + +#ifdef DEBUG + open_debug_output (); +#endif /* DEBUG */ + fromlen = sizeof (from); + if (getpeername (0, &from, &fromlen) < 0) + { + fprintf (stderr, "%s: ", argv[0]); + perror ("getpeername"); + _exit (1); + } + +/* MIT */ +#ifdef KEEPALIVE + if (setsockopt (0, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) + { + fprintf (stderr, "%s: ", argv[0]); + perror ("setsockopt (SO_KEEPALIVE)"); + } +#endif /* KEEPALIVE */ +/* MIT */ + doit (0, &from); +} +#endif /* DAEMON */ + + +reapchild () +{ + union wait status; + + while (wait3 (&status, WNOHANG, 0) > 0) + ; +} + +/* #ifdef TERMCAP */ +char termcap[1024]; +/* #endif /* TERMCAP */ + +#ifdef TERMINFO +char terminfo[64]; +#endif /* TERMINFO */ + +char *envinit[] = + { + "TERM=supdup", +/* #ifdef TERMCAP */ + termcap, +/* #endif /* TERMCAP */ +#ifdef TERMINFO + terminfo, +#endif /* TERMINFO */ + 0 + }; + +int cleanup (); + +char *host; +#ifdef TIOCSWINSZ +struct winsize ws; +#endif + +/* + * Get a pty, scan input lines. + */ +doit (f, who) + int f; + struct sockaddr_in *who; +{ + char *cp = pty_name, *ntoa (); + int i, p, cc, t; + struct sgttyb b; + struct hostent *hp; + + for (i = 0; i < 16; i++) + { + cp[strlen ("/dev/ptyq")] = "0123456789abcdef"[i]; + p = open (cp, O_RDWR, 0); + if (p > 0) + goto gotpty; + } + fatal (f, "All network ports in use"); + /*NOTREACHED*/ +gotpty: + dup2 (f, 0); + cp[strlen ("/dev/")] = 't'; +#ifdef TTYLOC + sprintf (ttyloc, "/tmp/ttyq%c.ttyloc", cp[strlen ("/dev/ttyq")]); + unlink (ttyloc); +#endif /* TTYLOC */ + t = open ("/dev/tty", O_RDWR, 0); + if (t >= 0) + { + ioctl (t, TIOCNOTTY, 0); + close (t); + } + t = open (cp, O_RDWR, 0); + if (t < 0) + fatalperror (f, cp, errno); + ioctl (t, TIOCGETP, &b); + /* MIT */ + b.sg_ispeed = B9600; + b.sg_ospeed = B9600; + /* MIT */ + b.sg_flags = XTABS | ANYP; /* punted CRMOD */ + ioctl (t, TIOCSETP, &b); + ioctl (p, TIOCGETP, &b); + b.sg_flags &= ~ECHO; + ioctl (p, TIOCSETP, &b); + sup_options (f); +#ifdef TIOCSWINSZ + ioctl (p, TIOCSWINSZ, &ws); +#endif /* TIOCSWINSZ */ + hp = gethostbyaddr (&who->sin_addr, sizeof (struct in_addr), + who->sin_family); + if (hp) + host = hp->h_name; + else + host = ntoa (who->sin_addr); + if ((i = fork ()) < 0) + fatalperror (f, "fork", errno); + if (i) + supdup (f, p); + + close (f); + close (p); + dup2 (t, 0); + dup2 (t, 1); + dup2 (t, 2); + close (t); +#ifdef BSD4_3 + /* Winning -p switch passes through environment */ + execle ("/bin/login", "login", "-p", "-h", host, 0, envinit); +#else +#ifdef MIT + /* Local /bin/login at ai.mit.edu machines hacked to pass TERM and TERMCAP */ + execle ("/bin/login", "login", "-h", host, 0, envinit); + fatalperror (2, "/bin/login", errno); +#else + /* Can't use /bin/login as that nukes TERM and TERMCAP. Cretins! */ + execle ("/usr/etc/supdup-login", "login", "-h", host, 0, envinit); + fatalperror (2, "/usr/etc/supdup-login", errno); +#endif /* MIT */ +#endif /* not BSD4_3 */ + /*NOTREACHED*/ +} + +fatal (f, msg) + int f; + char *msg; +{ + char buf[BUFSIZ]; + + (void) sprintf (buf, "supdupd: %s.\r\n", msg); + (void) write (f, buf, strlen (buf)); + exit (1); +} + +fatalperror (f, msg, errno) + int f; + char *msg; + int errno; +{ + char buf[BUFSIZ]; + extern char *sys_errlist[]; + + (void) sprintf (buf, "%s: %s", msg, sys_errlist[errno]); + fatal (f, buf); +} + +/* + * Main loop. Select from pty and network, and + * hand data to supdup receiver finite state machine. + */ +supdup (f, p) +{ + int on = 1; + char hostname[256]; + + net = f, pty = p; + ioctl (f, FIONBIO, &on); + ioctl (p, FIONBIO, &on); + signal (SIGTSTP, SIG_IGN); + signal (SIGCHLD, cleanup); + mode (ECHO|CRMOD, 0); + + /* + * Print supdup banner. + */ + gethostname (hostname, sizeof (hostname)); + sprintf (nfrontp, SBANNER, hostname, host); + nfrontp += strlen (nfrontp); + *nfrontp++ = TDNOP; + netflush (); + sleep (2); + + /* + * Show banner that getty never gave. + */ + + *nfrontp++ = TDCLR; + sprintf (nfrontp, BANNER, hostname, ""); + currline = 1; + currcol = 0; + nfrontp += strlen (nfrontp); + for (;;) + { + int ibits = 0, obits = 0; + register int c; + + /* + * Never look for input if there's still + * stuff in the corresponding output buffer + */ + if ((nfrontp - nbackp) || pcc > 0) + obits |= (1 << f); + else + ibits |= (1 << p); + if ((pfrontp - pbackp) || ncc > 0) + obits |= (1 << p); + else + ibits |= (1 << f); + if (ncc < 0 && pcc < 0) + break; + select (16, &ibits, &obits, 0, 0); + if (ibits == 0 && obits == 0) + { + sleep (5); + continue; + } + + /* + * Something to read from the network... + */ + if (ibits & (1 << f)) + { + ncc = read (f, netibuf, BUFSIZ); + if (ncc < 0 && errno == EWOULDBLOCK) + ncc = 0; + else + { + if (ncc <= 0) + break; + netip = netibuf; + } + } + + /* + * Something to read from the pty... + */ + if (ibits & (1 << p)) + { + pcc = read (p, ptyibuf, BUFSIZ); + if (pcc < 0 && errno == EWOULDBLOCK) + pcc = 0; + else + { + if (pcc <= 0) + break; + ptyip = ptyibuf; + } + } + + if (pcc > 0) + supxmit (); + if ((obits & (1 << f)) && (nfrontp - nbackp) > 0) + netflush (); + if (ncc > 0) + suprcv (); + if ((obits & (1 << p)) && (pfrontp - pbackp) > 0) + ptyflush (); + } + cleanup (); +} + +/* State for xmit fsm */ +#define XS_DATA 0 /* base state */ +#define XS_ESCAPE 1 /* supdup commands are escaped in TERMCAP */ +#define XS_MV0_V 2 /* getting vertical position for TDMV0 */ +#define XS_MV0_H 4 /* getting horizontal position for TDMV0 */ +#define XS_CRLF 6 /* got \r looking for \n */ +#define XS_LFCR 7 /* got \n looking for \r */ +#if (TDILP < 8) || (TDDLP < 8) || (TDICP < 8) || (TDDCP < 8) + you lose! +#endif +#define XS_ILINE TDILP /* waiting for number of lines to insert */ +#define XS_DLINE TDDLP /* waiting for number of lines to delete */ +#define XS_ICHAR TDICP /* waiting for number of chars to insert */ +#define XS_DCHAR TDDCP /* waiting for number of chars to delete */ + +/* Because of Un*x Brain Death(tm) + * characters with the 200 bit don't go through the terminal driver reliably + * and \004 won't go through a un*x at all pty (what sort of bozos wrote + * this sh*t?) + */ + +supxmit () +{ + static int state = XS_DATA; + register int c; + static int piece_o_state, piece_o_state_v; + + while (pcc > 0) + { + if ((&netobuf[BUFSIZ] - nfrontp) < 4) + /* Caller will flush pending output */ + return; + c = *ptyip++ & 0377; pcc--; + switch (state) + { + case XS_DATA: + switch (c) + { + case ITP_ESCAPE: + *nfrontp++ = c; + *nfrontp++ = c; + break; + + case KLUDGE_ESCAPE: + state = XS_ESCAPE; + break; + + case '\007': + *nfrontp++ = TDBEL; + break; + + case '\t': + currcol = (currcol + 8) & ~7; + if (currcol >= columns) + currcol = columns; + *nfrontp++ = TDMV0; + *nfrontp++ = currline; + *nfrontp++ = currcol; + break; + + case '\b': + currcol--; + if (currcol < 0) + currcol = 0; + *nfrontp++ = TDMV0; + *nfrontp++ = currline; + *nfrontp++ = currcol; + break; + + case '\r': + DPRINTF ("\n<>",0,0); + state = XS_CRLF; + break; + + case '\n': + DPRINTF ("\n<>",0,0); + state = XS_LFCR; + break; + + case '\0': + /* throw away nulls. Something is being + * a twit and padding even though it + * is not wanted! */ + /* (Of course, \0 is really a printable MIT Ascii character) */ + break; + + default: + if (currcol < columns) + { + currcol++; + *nfrontp++ = c; + } + else + { + /* unread-char and do newline */ + ptyip--; pcc++; + do_crlf (); + } + break; + } + break; + + case XS_ESCAPE: + c += 0176; + switch (c) + { + case TDCRL: + state = XS_DATA; + do_crlf (); + break; + + case TDFS: + currcol++; + state = XS_DATA; + *nfrontp++ = c; + break; + + case TDMV0: + state = XS_MV0_V; + piece_o_state = 0; + piece_o_state_v = 0; + break; + + case TDCLR: + DPRINTF ("\n<>",0,0); + currcol = 0; currline = 0; + state = XS_DATA; + *nfrontp++ = c; + break; + + case TDLF: + /* this is not in the SUPDUP spec */ + /* Move down one row vertically */ + state = XS_DATA; + if (currline < (lines - 1)) + currline++; + *nfrontp++ = TDMV0; + *nfrontp++ = currline; + *nfrontp++ = currcol; + break; + + case TDUP: + state = XS_DATA; + if (currline > 0) currline--; + *nfrontp++ = TDMV0; + *nfrontp++ = currline; + *nfrontp++ = currcol; + break; + + case TDILP: + case TDDLP: + case TDICP: + case TDDCP: + state = c; + piece_o_state = 0; + break; + + case KLUDGE_ESCAPE: + /* Really shouldn't get two */ + /* of these but it's happening */ + break; + + default: + state = XS_DATA; + *nfrontp++ = c; + break; + + } + break; + + + /* The newline algorithm is as follows: + * A \r causes the cursor to be sent to the + * beginning of the line unless there is a \n + * immediately following on the input. + * If the next character is a \n then a + * %TDCRL is sent. + * A lone \n causes the cursor to be moved + * straight down one line wrapping if necessary + * or doing a %TDCRL if at the bottom of the screen + * and it is a scrolling terminal. + * + * The CR and NL handling is way too complicated... + */ + case XS_LFCR: + { + DPRINTF ("\n<>",0,0); + if (c == '\r') + do_crlf (); + else + { + /* Got a \012 followed by something other than a \015 */ + /* Treat the \012 as `move down down one row */ + if (currline < (lines - 1)) + { + *nfrontp++ = TDMV0; + *nfrontp++ = ++currline; + *nfrontp++ = currcol; + } + else if (TOROL) + { + /* this is not the right thing, but + * what else can I do? */ + currcol = 0; + *nfrontp++ = TDCRL; + } + else + { + currline = 0; + *nfrontp++ = TDMV0; + *nfrontp++ = 0; + *nfrontp++ = currcol; + *nfrontp++ = TDEOL; + } + ptyip--; pcc++; /* unread-char */ + DPRINTF ("\n<>", *ptyip,0); + } + state = XS_DATA; + break; + } + + case XS_CRLF: + { + DPRINTF ("\n<>",0,0); + if (c == '\n') + do_crlf (); + else + { + /* \013 followed by something other than \010 */ + /* Treat the \010 as a request to move to start of row */ + currcol = 0; + *nfrontp++ = TDMV0; + *nfrontp++ = currline; + *nfrontp++ = 0; + ptyip--; pcc++; /* unread-char */ + DPRINTF ("\n<>", *ptyip,0); + } + state = XS_DATA; + break; + } + + case XS_MV0_V: + case XS_MV0_H: + case TDILP: + case TDDLP: + case TDICP: + case TDDCP: + { + DPRINTF ("\n<>", piece_o_state, c); + if (c >= '0' && c <= '9') + { + piece_o_state = piece_o_state * 10 + c - '0'; + if (piece_o_state >= lines && piece_o_state >= columns) + { + state = XS_DATA; + break; + } + } + else if (c != ';') + { + state = XS_DATA; + break; + } + else switch (state) + { + case XS_MV0_V: + piece_o_state_v = piece_o_state; + piece_o_state = 0; + state = XS_MV0_H; + break; + case XS_MV0_H: + currline = piece_o_state_v; + currcol = piece_o_state; + state = XS_DATA; + *nfrontp++ = TDMV0; + *nfrontp++ = currline; + *nfrontp++ = currcol; + break; + default: /* TDILP, TDDLP, RDICP, TDDCP */ + while (pcc > 4 && (ptyip[0] & 0377) == KLUDGE_ESCAPE && + (ptyip[1] & 0377) == state - 0176 && + (ptyip[2] & 0377) == '1' && + (ptyip[3] & 0377) == ';') + /* Merge successive single insert/delete-line/char requests + (pander to clients who don't understand TERMCAP + AL/DL (and less-importantly IC/DC) capabilities) */ + { + piece_o_state++; + pcc -= 4; + ptyip += 4; + } + *nfrontp++ = state; + *nfrontp++ = piece_o_state; + if (state == TDILP || state == TDDLP) + { + /* Just to be on the safe side */ + currcol = 0; + *nfrontp++ = TDMV0; + *nfrontp++ = currline; + *nfrontp++ = currcol; + } + state = XS_DATA; + break; + } + DPRINTF ("\n<>", piece_o_state_v, piece_o_state); + break; + } + + default: + state = XS_DATA; + break; + } + } +} + +do_crlf () +{ + currcol = 0; + if (currline < (lines - 1)) + { + *nfrontp++ = TDCRL; + currline++; + } + else if (TOROL) + *nfrontp++ = TDCRL; + else + { + currline = 0; + *nfrontp++ = TDMV0; + *nfrontp++ = 0; + *nfrontp++ = 0; + *nfrontp++ = TDEOL; + } +} + + +/* + * State for recv fsm + */ + +/* base state */ +#define RS_DATA 0 + +/* recieved ITP_ESCAPE (034) Waiting for `m' */ +#define RS_ITP_ESCAPE 1 +/* received ITP_ESCAPE, `m'>#o100 + Waiting for `n'. + Char will be (+ (* (- `m' #o100) #o200) `n') */ +#define RS_BUCKY 2 + +/* Recived ITP_ESCAPE, ITP_FLOW_CONTROL_INCREASE + Ignore next char, since un*x can't hack real, winning, flow control */ +#define RS_FLOW_CONTROL_INCREASE 3 + +/* Recived ITP_ESCAPE, ITP_CURSORPOS + Waiting for `row' */ +#define RS_CURSORPOS_1 4 +/* Recived ITP_ESCAPE, ITP_CURSORPOS, `row' + Waiting for `column' */ +#define RS_CURSORPOS_2 5 + +/* received SUPDUP_ESCAPE (#o300) + Waiting for `m' */ +#define RS_SUPDUP_ESCAPE 6 + +/* received SUPDUP_ESCAPE, SUPDUP_LOCATION. + Now receiving 000-terminated + location string */ +#define RS_LOCATION 7 + +suprcv () +{ + register int c; + + static int state = RS_DATA; + static int piece_o_state = 69; + + while ((ncc > 0) && + /* Caller must flush pending output */ + ((&ptyobuf[BUFSIZ] - pfrontp) > 3)) + { + c = *netip++ & 0377; ncc--; + switch (state) + { + case RS_DATA: + { + if (c == SUPDUP_ESCAPE) + state = RS_SUPDUP_ESCAPE; + else if (c == ITP_ESCAPE) + state = RS_ITP_ESCAPE; + else + *pfrontp++ = c; + break; + } + + case RS_ITP_ESCAPE: + { + if (c & 0100) + { + piece_o_state = c; + state = RS_BUCKY; + } + else switch (c) + { + case ITP_ESCAPE: + *pfrontp++ = c; + state = RS_DATA; + break; + case ITP_PIATY: + /* %piaty --- user's screen is munged. + Cretinous unix provides no way to use this. + Conceivably we could send through a c-L character (barf!) + */ + case ITP_STOP_OUTPUT: + case ITP_RESTART_OUTPUT: + case ITP_FLOW_CONTROL_START: + case ITP_FLOW_CONTROL_END: + /* ignore it */ + state = RS_DATA; + break; + case ITP_FLOW_CONTROL_INCREASE: + state = RS_FLOW_CONTROL_INCREASE; + break; + case ITP_CURSORPOS: + /* read cursorpos -- v then h */ + state = RS_CURSORPOS_1; + break; + default: /* huh?! */ + state = RS_DATA; + break; + } + break; + } + + case RS_BUCKY: + { + register int bucky; + + bucky = ITP_CHAR (piece_o_state, c); + /* unix supdup server uses 0237 (CTL_PREFIX) as a control escape. + * c-a 001 + * m-a 341 + * c-m-a 201 + * c-1 237 061 + * m-1 261 + * c-m-1 237 261 + * c-m-_ 237 237 + */ + + switch (bucky) + { + case SUPDUP_HELP_KEY: + c = 'h' & 037; /* hack for Help key */ + break; + case SUPDUP_ESCAPE_KEY: + c = '\033'; + break; + case SUPDUP_SUSPEND_KEY: + c = 'z' & 037; + break; + case SUPDUP_CLEAR_KEY: + c = -1; + break; + default: + c = bucky & 0177; + if (bucky & ITP_TOP) + c &= 037; /* This is pretty random -- Mly */ + if (bucky & ITP_CTL) + { + if ((c >= 'a' && c <= 'z') || + (c >= '@' && c <= 'Z') || + (c >= '\\' && c <= '_')) + c &= 037; + else + *pfrontp++ = CTL_PREFIX; + } + if (bucky & ITP_MTA) + c |= 0200; + if (c == CTL_PREFIX) + /* Double control prefix to send 0237 (200 + ^_) + through pseudo-transparently */ + *pfrontp++ = c; + } + if (c >= 0) + *pfrontp++ = c; + state = RS_DATA; + break; + } + + case RS_FLOW_CONTROL_INCREASE: + /* Ignore it -- we can't hack this */ + state = RS_DATA; + break; + + case RS_CURSORPOS_1: + piece_o_state = c; + state = RS_CURSORPOS_2; + break; + + case RS_CURSORPOS_2: + { + /* read cursorpos -- v then h */ + if ((piece_o_state < lines) && (c < columns)) + { + currcol = piece_o_state; + currline = c; + } + state = RS_DATA; + } + + + case RS_SUPDUP_ESCAPE: + switch (c) + { + case SUPDUP_LOGOUT: + cleanup (); + + case SUPDUP_LOCATION: + state = RS_LOCATION; + break; + + default: /* WTF? */ + state = RS_DATA; + break; + } + break; + + case RS_LOCATION: + { + static char buf[BUFSIZ]; + static char *p = &buf[0]; + int f; + + if (c != '\000') + { + if (p - buf < BUFSIZ) + *p++ = c; + } + else + { +#ifdef TTYLOC + f = creat (ttyloc, 0644); + if (f > 0) + { + (void) write (f, buf, p - buf); + (void) close (f); + } +#endif /* TTYLOC */ + state = RS_DATA; + } + } + break; + } + } +} + +mode (on, off) + int on, off; +{ + struct sgttyb b; + + ptyflush (); + ioctl (pty, TIOCGETP, &b); + b.sg_flags |= on; + b.sg_flags &= ~off; + ioctl (pty, TIOCSETP, &b); +} + +ptyflush () +{ + int n; + + if ((n = pfrontp - pbackp) > 0) + n = write (pty, pbackp, n); + if (n < 0) + return; + pbackp += n; + if (pbackp == pfrontp) + pbackp = pfrontp = ptyobuf; +} + +netflush () +{ + int n; + + if ((n = nfrontp - nbackp) > 0) + { + n = write (net, nbackp, n); +#ifdef DEBUG + if (debug_output) + { + fflush (debug_output); + (void) write (fileno (debug_output), nbackp, n); + } +#endif /* DEBUG */ + } + if (n < 0) + { + if (errno == EWOULDBLOCK) + return; + /* should blow this guy away... */ + return; + } + nbackp += n; + if (nbackp == nfrontp) + nbackp = nfrontp = netobuf; +} + +cleanup () +{ +#ifdef TERMINFO + clean_terminfo (); +#endif /* TERMINFO */ + + rmut (); +#ifdef TTYLOC + unlink (ttyloc); +#endif /* TTYLOC */ + vhangup (); /* XXX */ + shutdown (net, 2); + kill (0, SIGKILL); + exit (1); +} + +#ifdef TERMINFO +/* Cleans up the files created for the TERMINFO stuff. + */ +clean_terminfo () +{ + char dir[128]; + int pid; + + pid = getpid (); + sprintf (dir, "/tmp/%d/s/supdup", pid); + unlink (dir); + sprintf (dir, "/tmp/%d/s", pid); + rmdir (dir); + sprintf (dir, "/tmp/%d", pid); + rmdir (dir); +} + +#endif /* TERMINFO */ + + +#include + +struct utmp wtmp; +char wtmpf[] = "/usr/adm/wtmp"; +char utmp[] = "/etc/utmp"; +#define SCPYN(a, b) strncpy (a, b, sizeof (a)) +#define SCMPN(a, b) strncmp (a, b, sizeof (a)) + +rmut () +{ + register f; + int found = 0; + + f = open (utmp, O_RDWR, 0); + if (f >= 0) + { + while (sizeof (wtmp) == read (f, (char *) &wtmp, sizeof (wtmp))) + { + if (SCMPN (wtmp.ut_line, pty_name + strlen ("/dev/")) || + wtmp.ut_name[0] == 0) + continue; + lseek (f, - (long)sizeof (wtmp), 1); + SCPYN (wtmp.ut_name, ""); + SCPYN (wtmp.ut_host, ""); + time (&wtmp.ut_time); + write (f, (char *) &wtmp, sizeof (wtmp)); + found++; + } + close (f); + } + if (found) + { + f = open (wtmpf, O_WRONLY, 0); + if (f >= 0) + { + SCPYN (wtmp.ut_line, pty_name + strlen ("/dev/")); + SCPYN (wtmp.ut_name, ""); + SCPYN (wtmp.ut_host, ""); + time (&wtmp.ut_time); + lseek (f, (long) 0, 2); + write (f, (char *) &wtmp, sizeof (wtmp)); + close (f); + } + } + chmod (pty_name, 0666); + chown (pty_name, 0, 0); + pty_name[strlen ("/dev/")] = 'p'; + chmod (pty_name, 0666); + chown (pty_name, 0, 0); +} + +/* + * Convert network-format internet address + * to base 256 d.d.d.d representation. + */ +char * +ntoa (in) + struct in_addr in; +{ + static char b[18]; + register char *p; + + p = (char *) ∈ +#define UC(b) (((int)b)&0xff) + sprintf (b, "%d.%d.%d.%d", UC (p[0]), UC (p[1]), UC (p[2]), UC (p[3])); + return (b); +} + +/* Read the 36 bit options from the net setting variables and create + * the TERMCAP environment variable. + */ +sup_options (net) + int net; +{ + char temp[6]; + int count; + int tcmxh, tcmxv; + + read (net, temp, 6); /* Read count */ + count = -((-1 << 6) | temp[2]); + if (count--) + { + read (net, temp, 6); /* Discard TCTYP */ + if (count--) + { + read (net, ttyopt, 6); + if (count--) + { + read (net, temp, 6); + tcmxv = (temp[5] & 0377) | ((temp[4] & 0377) << 6); +#if 0 /* No longer needed, since we now encode positions using %d */ + /* Un*x braindeath (tm) */ + if (tcmxv >= 128 - 5) tcmxv = 128 - 5 - 1; +#endif 0 + if (count--) + { + read (net, temp, 6); + /* The 1 + is because supdup spec transmits 1 - columns */ + tcmxh = 1 + (temp[5] & 0377) | ((temp[4] & 0377) << 6); +#if 0 + /* Un*x braindeath (tm) */ + if (tcmxh >= 128 - 5) tcmxh = 128 - 5 - 1; +#endif 0 + if (count--) + { + read (net, temp, 6); + ttyrol = temp[5] & 077; + while (count--) + read (net, temp, 6); + } + } + } + } + } + + lines = tcmxv; + columns = tcmxh; + +#ifdef TIOCSWINSZ + ws.ws_row = lines; + ws.ws_col = columns; + ws.ws_xpixel = columns * 6; + ws.ws_ypixel = lines * 10; +#endif /* TIOCSWINSZ */ + + sprintf (termcap, "TERMCAP=SD|supdup|SUPDUP virtual terminal:co#%d:li#%d:", + columns, lines); + strcat (termcap, "vb=\\177\\023:nd=\\177\\020:MT:"); + strcat (termcap, "cl=\\177\\022:so=\\177\\031:se=\\177\\032:pt:"); + if (TOERS) + strcat (termcap, "ce=\\177\\005:ec=\\177\\006:cd=\\177\\004:"); + if (TOMVB) + strcat (termcap, "bs:"); + if (TOOVR) + strcat (termcap, "os:"); + if (TOMVU) + { + strcat (termcap, "up=\\177\\041:cm=\\177\\021%d;%d;:"); + strcat (termcap, "do=\\177\\014:nl=\\177\\014:"); + } + if (TOLID) + { + strcat (termcap, "al=\\177\\0251;:dl=\\177\\0261;:"); + strcat (termcap, "AL=\\177\\025%d;:DL=\\177\\026%d;:"); + } + if (TOCID) + { + strcat (termcap, "mi:im=:ei=:dm=:ed=:"); + strcat (termcap, "ic=\\177\\0271;:dc=\\177\\0301;:"); + strcat (termcap, "IC=\\177\\027%d;:DC=\\177\\030%d;:"); + } + if (!TOROL) + strcat (termcap, "ns:"); +/*if (TOFCI) -- I don't think that always doing this can hurt much */ + strcat (termcap, "km:"); + + /* We only wrap if a character is written when we are + -past- the last column. This way we avoid brain-dead unwanted + scrolling, whilst still allowing un*x' completely brain lack of + terminal-handling (which assumes that directly sending an + arbitrary-length string containing no newlines to the terminal + will result in the user seeing all of it. + As PGS says, ``filthy damned unix pinheads.'' */ + /* strcat (termcap, "am:"); We don't lose in this way any more. */ + /* Not-widely-known flag, which says that writing in the last column of + the last line doesn't cause idiotic scrolling */ + strcat (termcap, "LP:"); + /* Not-widely-known flag, which says not to use idiotic + c-s/c-q so-called ``flow control'' under any circumstances. */ + strcat (termcap, "NF:"); + +#ifdef TERMINFO + init_terminfo (); +#endif /* TERMINFO */ +} + + +#ifdef TERMINFO + +char names[] = "supdup|sd|supdup virtual terminal"; +#define MAGIC_NUM 0432 + +struct head + { + short magic; + short name_len; + short bools_len; + short nums_len; + short str_len; + short strtab_len; + } header; + +unsigned char Booleans[BOOLCOUNT + 1]; +short Numbers[NUMCOUNT]; +short Strings[STRCOUNT]; +char String_Table[] = { +#define FLASH_SCREEN 0 + '\177', '\023', '\0', +#define CURSOR_RIGHT FLASH_SCREEN + 3 + '\177', '\020', '\0', +#define CLEAR_SCREEN CURSOR_RIGHT + 3 + '\177', '\022', '\0', +#define ENTER_STANDOUT_MODE CLEAR_SCREEN + 3 + '\177', '\031', '\0', +#define EXIT_STANDOUT_MODE ENTER_STANDOUT_MODE + 3 + '\177', '\032', '\0', +#define CLR_EOL EXIT_STANDOUT_MODE + 3 + '\177', '\005', '\0', +#define CLR_EOS CLR_EOL + 3 + '\177', '\004', '\0', +#define CURSOR_UP CLR_EOS + 3 + '\177', '\041', '\0', +#define CURSOR_DOWN CURSOR_UP + 3 + '\177', '\014', '\0', +#define NEWLINE CURSOR_DOWN + 3 + '\177', '\011', '\0', /* this does cursor_down (\014) in termcap */ +#define CURSOR_ADDRESS NEWLINE + 3 + /* %p1%d;%p2%d; */ + '\177', '\021', + '%', 'p', '1', '%', 'd', ';', '%', 'p', '2', '%', 'd', ';', '\0', +#define INSERT_LINE CURSOR_ADDRESS + 15 + '\177', '\025', '1', ';', '\0', +#define DELETE_LINE INSERT_LINE + 5 + '\177', '\026', '1', ';', '\0', +#define PARM_INSERT_LINE DELETE_LINE + 5 + '\177', '\025', '%', 'p', '1', '%', 'd', ';', '\0', +#define PARM_DELETE_LINE PARM_INSERT_LINE + 9 + '\177', '\026', '%', 'p', '1', '%', 'd', ';', '\0', +#define CURSOR_LEFT PARM_DELETE_LINE + 9 + /* >> BARF!! */ + '', '\0', +#define DELETE_CHARACTER CURSOR_LEFT + 2 + '\177', '\030', '1', ';', '\0', +#define INSERT_CHARACTER DELETE_CHARACTER + 5 + '\177', '\027', '1', ';', '\0', +#define PARM_DCH INSERT_CHARACTER + 5 + '\177', '\030', '%', 'p', '1', '%', 'd', ';', '\0', +#define PARM_ICH PARM_DCH + 9 + '\177', '\027', '%', 'p', '1', '%', 'd', ';', '\0', +#define STRTABLEN PARM_ICH + 9 + 10 +}; + + +/* This routine sets up the files and environment variables for using the + * TERMINFO data base. + */ +init_terminfo () +{ + register int i; + int file; + int pid; + char directory[128]; + + pid = getpid (); + sprintf (directory, "/tmp/%d", pid); + mkdir (directory, 0777); + sprintf (terminfo, "TERMINFO=%s", directory); + strcat (directory, "/s"); + mkdir (directory, 0777); + strcat (directory, "/supdup"); + + file = open (directory, O_WRONLY | O_CREAT, 0777); + if (file <= 0) cleanup (); + + for (i = 0; i < BOOLCOUNT + 1; i++) + Booleans[i] = 0; + for (i = 0; i < NUMCOUNT; i++) + Numbers[i] = -1; + for (i = 0; i < STRCOUNT; i++) + Strings[i] = -1; + + header.magic = MAGIC_NUM; + header.name_len = strlen (names) + 1; + header.bools_len = BOOLCOUNT; + header.nums_len = NUMCOUNT; + header.str_len = STRCOUNT; + header.strtab_len = STRTABLEN; + + lines = tcmxv; + columns = tcmxh; + auto_right_margin = 0; + flash_screen = FLASH_SCREEN; + cursor_right = CURSOR_RIGHT; + clear_screen = CLEAR_SCREEN; + enter_standout_mode = ENTER_STANDOUT_MODE; + exit_standout_mode = EXIT_STANDOUT_MODE; + init_tabs = 8; + if (TOERS) + { + clr_eol = CLR_EOL; + clr_eos = CLR_EOS; + } + if (TOMVB) + cursor_left = CURSOR_LEFT; + if (TOOVR) + over_strike = 1; + if (TOMVU) + { + cursor_up = CURSOR_UP; + cursor_down = CURSOR_DOWN; + newline = NEWLINE; + cursor_address = CURSOR_ADDRESS; + } + if (TOLID) + { + insert_line = INSERT_LINE; + delete_line = DELETE_LINE; + parm_insert_line = PARM_INSERT_LINE; + parm_delete_line = PARM_DELETE_LINE; + } + if (TOCID) + { + insert_character = INSERT_CHARACTER; + delete_character = DELETE_CHARACTER; + parm_dch = PARM_DCH; + parm_ich = PARM_ICH; + } +/*if (TOFCI) -- I don't think that always doing this can hurt much */ + has_meta_key = 1; + + write (file, &header, sizeof (struct head)); + write (file, names, header.name_len); + write (file, Booleans, (header.name_len + header.bools_len) & 1 + ? header.bools_len + 1 + : header.bools_len); + write (file, Numbers, 2 * header.nums_len); + write (file, Strings, 2 * header.str_len); + write (file, String_Table, header.strtab_len + 5); + +} + +#endif /* TERMINFO */ diff --git a/contrib/supdup/termcap.h b/contrib/supdup/termcap.h new file mode 100644 index 0000000..a676df3 --- /dev/null +++ b/contrib/supdup/termcap.h @@ -0,0 +1,171 @@ + +/* + * termcap.h -- definitions of the variables in which + * the termcap info is kept + */ + +#define TCAPDEFS \ + TCFLG(am, "has automatic margins"),\ + TCFLG(bs, "has ^H backspace"),\ + TCFLG(hc, "hardcopy term"),\ + TCFLG(km, "has meta key"),\ + TCFLG(mi, "safe to move in insert mode"),\ + TCFLG(nc, "no working CR"),\ + TCFLG(pt, "has hardware tabs"),\ + TCFLG(ul, "underscore can overstrike"),\ + TCFLG(ns, "wraps rather than scrolls"),\ + TCFLG(MT, "has meta key (xterm)"),\ + \ + TCSTR(al, "Add new blank line"),\ + TCSTR(le, "Move back one position"),\ + TCSTR(bt, "Back tab"),\ + TCSTR(cd, "Clear to end of display"),\ + TCSTR(ce, "Clear to end of line"),\ + TCSTR(ch, "Like CM but horizontal motion only"),\ + TCSTR(cl, "Clear screen"),\ + TCSTR(cm, "Cursor motion"),\ + TCSTR(cr, "Carriage return (default '^M')"),\ + TCSTR(cs, "Change scrolling region (vt100), like CM"),\ + TCSTR(cv, "Like CM but vertical only"),\ + TCSTR(dc, "Delete character"),\ + TCSTR(dl, "Delete line"),\ + TCSTR(dm, "Delete mode"),\ + TCSTR(do, "Down one line"),\ + TCSTR(ed, "End delete mode"),\ + TCSTR(ei, "End insert mode"),\ + TCSTR(ho, "Home cursor"),\ + TCSTR(ic, "Insert character"),\ + TCSTR(im, "Insert mode (enter)"),\ + TCSTR(is, "Terminal initialization string"),\ + TCSTR(ll, "Last line, first column"),\ + TCSTR(nd, "Non-destructive space (cursor right)"),\ + TCSTR(nw, "Newline (behave like CR + LF)"),\ + TCSTR(pc, "Pad character"),\ + TCSTR(sf, "Scroll forward"),\ + TCSTR(sr, "Scroll reverse"),\ + TCSTR(ta, "Tab (other than '^I' or with padding)"),\ + TCSTR(te, "String to end programs that use CM"),\ + TCSTR(ti, "String to begin programs that use CM"),\ + TCSTR(up, "Upline (cursor up)"),\ + TCSTR(vb, "Visible bell"),\ + TCSTR(ve, "Sequence to end open/visual mode"),\ + TCSTR(vs, "Sequence to start open/visual mode"),\ + TCSTR(se, "End standout mode"),\ + TCSTR(so, "Begin standout mode"),\ + TCSTR(DC, "Delete n characters"),\ + TCSTR(IC, "Insert n characters"),\ + TCSTR(DL, "Delete n lines"),\ + TCSTR(AL, "xInsert n lines),\" + \ + TCNUM(co, "Number of columns in a line"),\ + TCNUM(dB, "Backspace delay"),\ + TCNUM(dC, "Carriage return delay"),\ + TCNUM(dN, "Newline delay"),\ + TCNUM(dT, "Tab delay "),\ + TCNUM(li, "Number of lines on screen") + + +enum tcaps { +#define TCSTR(tc,comm) TC_##tc##_s +#define TCNUM(tc,comm) TC_##tc##_n +#define TCFLG(tc,comm) TC_##tc##_f + TCAPDEFS +#undef TCSTR +#undef TCNUM +#undef TCFLG +}; + +/* Actually declare the vars now */ +#define TCSTR(tc,comm) static char *TC_##tc##_s = NULL; +#define TCNUM(tc,comm) static int TC_##tc##_n = 0; +#define TCFLG(tc,comm) static int TC_##tc##_f = 0; + TCAPDEFS +#undef TCSTR +#undef TCNUM +#undef TCFLG + +struct tcent { + char *tcname; + int tctyp; + void *tcval; +}; +struct tcent tcaptab[] = { +#define TCSTR(tc,comm) {#tc, TCTYP_STR, (void *)&TC_##tc##_s} +#define TCNUM(tc,comm) {#tc, TCTYP_NUM, (void *)&TC_##tc##_n}} +#define TCFLG(tc,comm) {#tc, TCTYP_FLG, (void *)&TC_##tc##_f}} + TCAPDEFS +#undef TCSTR +#undef TCNUM +#undef TCFLG +} + +#define TCSTR(tc) (TC_##tc##_s) +#define TCNUM(tc) (TC_##tc##_n) +#define TCFLG(tc) (TC_##tc##_f) + +#define auto_right_margin TCFLG(am) /* Terminal has automatic margins */ +#define BS TCFLG(bs) /* Terminal can backspace with '^H' */ +#define hard_copy TCFLG(hc) /* Hardcopy terminal */ +#define has_meta_key TCFLG(km) /* Has meta key */ +#define move_insert_mode TCFLG(mi) /* Safe to move while in insert mode */ +#define NC TCFLG(nc) /* No correctly working carriage ret */ +#define PT TCFLG(pt) /* Has hardware tabs */ +#define transparent_underline TCFLG(ul) /* '_' overstrikes */ +#define no_scroll TCFLG(ns) /* Wraps rather than scrolls */ +#define also_has_meta_key TCFLG(MT) /* KLH: Another flag for meta key */ + /* (xterm is fond of this one) */ + +#define insert_line TCSTR(al) /* Add new blank line */ +#define cursor_left TCSTR(le) /* Move back one position */ +#define back_tab TCSTR(bt) /* Back tab */ +#define clr_eos TCSTR(cd) /* Clear to end of display */ +#define clr_eol TCSTR(ce) /* Clear to end of line */ +#define CH TCSTR(ch) /* Like CM but horiz motion only */ +#define clear_screen TCSTR(cl) /* Clear screen */ +#define cursor_address TCSTR(cm) /* Cursor motion */ +#define carriage_return TCSTR(cr) /* Carriage return (default '^M') */ +#define CS TCSTR(cs) /* Change scrolling region (vt100), like CM */ +#define CV TCSTR(cv) /* Like CM but vertical only */ +#define delete_character TCSTR(dc) /* Delete character */ +#define delete_line TCSTR(dl) /* Delete line */ +#define DM TCSTR(dm) /* Delete mode */ +#define cursor_down TCSTR(do) /* Down one line */ +#define ED TCSTR(ed) /* End delete mode */ +#define EI TCSTR(ei) /* End insert mode */ +#define cursor_home TCSTR(ho) /* Home cursor */ +#define insert_character TCSTR(ic) /* Insert character */ +#define IM TCSTR(im) /* Insert mode (enter) */ +#define IS TCSTR(is) /* Terminal initialization string */ +#define LL TCSTR(ll) /* Last line, first column */ +#define cursor_right TCSTR(nd) /* Non-destructive space (cursor right) */ +#if 0 /* Broken? */ +# define fresh_line TCSTR(nw) /* Move to start of fresh line */ +#endif +#define PC TCSTR(pc) /* Pad character */ +#define SF TCSTR(sf) /* Scroll forward */ +#define SR TCSTR(sr) /* Scroll reverse */ +#define TA TCSTR(ta) /* Tab (other than '^I' or with padding) */ +#define TE TCSTR(te) /* String to end programs that use CM */ +#define TI TCSTR(ti) /* String to begin programs that use CM */ +#define cursor_up TCSTR(up) /* Upline (cursor up) */ +#define flash_screen TCSTR(vb) /* Visible bell */ +#define VE TCSTR(ve) /* Sequence to end open/visual mode */ +#define VS TCSTR(vs) /* Sequence to start open/visual mode */ +#define exit_standout_mode TCSTR(se) /* End standout mode */ +#define enter_standout_mode TCSTR(so) /* Begin standout mode */ +#define parm_dch TCSTR(DC) /* Delete n characters */ +#define parm_ich TCSTR(IC) /* Insert n characters */ +#define parm_delete_line TCSTR(DL) /* Delete n lines */ +#define parm_insert_line TCSTR(AL) /* Insert n lines */ + +#define columns TCNUM(co) /* co Number of columns in a line */ +#define BSdelay TCNUM(dB) /* dB Backspace delay */ +#define CRdelay TCNUM(dC) /* dC Carriage return delay */ +#define NLdelay TCNUM(dN) /* dN Newline delay */ +#define TAdelay TCNUM(dT) /* dT Tab delay */ +#define lines TCNUM(li) /* li Number of lines on screen */ + + +/* Things defined to look more like TERMINFO */ +#define over_strike 0 +#define bell 0 diff --git a/contrib/supdup/termcaps.h b/contrib/supdup/termcaps.h new file mode 100644 index 0000000..44ccf62 --- /dev/null +++ b/contrib/supdup/termcaps.h @@ -0,0 +1,178 @@ + +/* + * termcaps.h -- definitions of the variables in which + * the termcap info is kept + * KLH: Totally revised to keep things in sync + */ + +/* Define macro of all interesting caps. If compiler chokes, + de-macro it into separate file which can be included multiple times. + */ +#define TCAPDEFS \ + TCFLG(am, "has automatic margins"),\ + TCFLG(bs, "has ^H backspace"),\ + TCFLG(hc, "hardcopy term"),\ + TCFLG(km, "has meta key"),\ + TCFLG(mi, "safe to move in insert mode"),\ + TCFLG(nc, "no working CR"),\ + TCFLG(pt, "has hardware tabs"),\ + TCFLG(ul, "underscore can overstrike"),\ + TCFLG(ns, "wraps rather than scrolls"),\ + TCFLG(MT, "has meta key (xterm)"),\ + \ + TCSTR(al, "Add new blank line"),\ + TCSTR(le, "Move back one position"),\ + TCSTR(bt, "Back tab"),\ + TCSTR(cd, "Clear to end of display"),\ + TCSTR(ce, "Clear to end of line"),\ + TCSTR(ch, "Like CM but horizontal motion only"),\ + TCSTR(cl, "Clear screen"),\ + TCSTR(cm, "Cursor motion"),\ + TCSTR(cr, "Carriage return (default '^M')"),\ + TCSTR(cs, "Change scrolling region (vt100), like CM"),\ + TCSTR(cv, "Like CM but vertical only"),\ + TCSTR(dc, "Delete character"),\ + TCSTR(dl, "Delete line"),\ + TCSTR(dm, "Delete mode"),\ + TCSTR(do, "Down one line"),\ + TCSTR(ed, "End delete mode"),\ + TCSTR(ei, "End insert mode"),\ + TCSTR(ho, "Home cursor"),\ + TCSTR(ic, "Insert character"),\ + TCSTR(im, "Insert mode (enter)"),\ + TCSTR(is, "Terminal initialization string"),\ + TCSTR(ll, "Last line, first column"),\ + TCSTR(nd, "Non-destructive space (cursor right)"),\ + TCSTR(nw, "Newline (behave like CR + LF)"),\ + TCSTR(pc, "Pad character"),\ + TCSTR(sf, "Scroll forward"),\ + TCSTR(sr, "Scroll reverse"),\ + TCSTR(ta, "Tab (other than '^I' or with padding)"),\ + TCSTR(te, "String to end programs that use CM"),\ + TCSTR(ti, "String to begin programs that use CM"),\ + TCSTR(up, "Upline (cursor up)"),\ + TCSTR(vb, "Visible bell"),\ + TCSTR(ve, "Sequence to end open/visual mode"),\ + TCSTR(vs, "Sequence to start open/visual mode"),\ + TCSTR(se, "End standout mode"),\ + TCSTR(so, "Begin standout mode"),\ + TCSTR(DC, "Delete n characters"),\ + TCSTR(IC, "Insert n characters"),\ + TCSTR(DL, "Delete n lines"),\ + TCSTR(AL, "xInsert n lines"),\ + \ + TCNUM(co, "Number of columns in a line"),\ + TCNUM(dB, "Backspace delay"),\ + TCNUM(dC, "Carriage return delay"),\ + TCNUM(dN, "Newline delay"),\ + TCNUM(dT, "Tab delay "),\ + TCNUM(li, "Number of lines on screen") + + +/* Define indices into table. Note type distinction is reflected + in index names, so as to catch improper references. +*/ +enum tcaps { +#define TCSTR(tc,comm) TCI_##tc##_s +#define TCNUM(tc,comm) TCI_##tc##_n +#define TCFLG(tc,comm) TCI_##tc##_f + TCAPDEFS +#undef TCSTR +#undef TCNUM +#undef TCFLG +}; + +struct tcent { + char *tcname; + int tctyp; + union { + char *str; + int num; + int flg; + } tcval; +}; +#define TCTYP_STR 0 +#define TCTYP_NUM 1 +#define TCTYP_FLG 2 + +struct tcent tcaptab[] = { +#define TCSTR(tc,comm) {#tc, TCTYP_STR} +#define TCNUM(tc,comm) {#tc, TCTYP_NUM} +#define TCFLG(tc,comm) {#tc, TCTYP_FLG} + TCAPDEFS +#undef TCSTR +#undef TCNUM +#undef TCFLG +}; + +#define TCSTR(tc) (tcaptab[TCI_##tc##_s].tcval.str) +#define TCNUM(tc) (tcaptab[TCI_##tc##_n].tcval.num) +#define TCFLG(tc) (tcaptab[TCI_##tc##_f].tcval.flg) + +#define auto_right_margin TCFLG(am) /* Terminal has automatic margins */ +#define BS TCFLG(bs) /* Terminal can backspace with '^H' */ +#define hard_copy TCFLG(hc) /* Hardcopy terminal */ +#define has_meta_key TCFLG(km) /* Has meta key */ +#define move_insert_mode TCFLG(mi) /* Safe to move while in insert mode */ +#define NC TCFLG(nc) /* No correctly working carriage ret */ +#define PT TCFLG(pt) /* Has hardware tabs */ +#define transparent_underline TCFLG(ul) /* '_' overstrikes */ +#define no_scroll TCFLG(ns) /* Wraps rather than scrolls */ +#define also_has_meta_key TCFLG(MT) /* KLH: Another flag for meta key */ + /* (xterm is fond of this one) */ +#define insert_line TCSTR(al) /* Add new blank line */ +#define cursor_left TCSTR(le) /* Move back one position */ +#define back_tab TCSTR(bt) /* Back tab */ +#define clr_eos TCSTR(cd) /* Clear to end of display */ +#define clr_eol TCSTR(ce) /* Clear to end of line */ +#define CH TCSTR(ch) /* Like CM but horiz motion only */ +#define clear_screen TCSTR(cl) /* Clear screen */ +#define cursor_address TCSTR(cm) /* Cursor motion */ +#define carriage_return TCSTR(cr) /* Carriage return (default '^M') */ +#define CS TCSTR(cs) /* Change scrolling region (vt100), like CM */ +#define CV TCSTR(cv) /* Like CM but vertical only */ +#define delete_character TCSTR(dc) /* Delete character */ +#define delete_line TCSTR(dl) /* Delete line */ +#define DM TCSTR(dm) /* Delete mode */ +#define cursor_down TCSTR(do) /* Down one line */ +#define ED TCSTR(ed) /* End delete mode */ +#define EI TCSTR(ei) /* End insert mode */ +#define cursor_home TCSTR(ho) /* Home cursor */ +#define insert_character TCSTR(ic) /* Insert character */ +#define IM TCSTR(im) /* Insert mode (enter) */ +#define IS TCSTR(is) /* Terminal initialization string */ +#define LL TCSTR(ll) /* Last line, first column */ +#define cursor_right TCSTR(nd) /* Non-destructive space (cursor right) */ +#if 0 /* Broken? */ +# define fresh_line TCSTR(nw) /* Move to start of fresh line */ +#else +# define fresh_line (0) /* Move to start of fresh line */ +#endif +#define PC TCSTR(pc) /* Pad character */ +#define SF TCSTR(sf) /* Scroll forward */ +#define SR TCSTR(sr) /* Scroll reverse */ +#define TA TCSTR(ta) /* Tab (other than '^I' or with padding) */ +#define TE TCSTR(te) /* String to end programs that use CM */ +#define TI TCSTR(ti) /* String to begin programs that use CM */ +#define cursor_up TCSTR(up) /* Upline (cursor up) */ +#define flash_screen TCSTR(vb) /* Visible bell */ +#define VE TCSTR(ve) /* Sequence to end open/visual mode */ +#define VS TCSTR(vs) /* Sequence to start open/visual mode */ +#define exit_standout_mode TCSTR(se) /* End standout mode */ +#define enter_standout_mode TCSTR(so) /* Begin standout mode */ +#define parm_dch TCSTR(DC) /* Delete n characters */ +#define parm_ich TCSTR(IC) /* Insert n characters */ +#define parm_delete_line TCSTR(DL) /* Delete n lines */ +#define parm_insert_line TCSTR(AL) /* Insert n lines */ + +#define columns TCNUM(co) /* co Number of columns in a line */ +#define BSdelay TCNUM(dB) /* dB Backspace delay */ +#define CRdelay TCNUM(dC) /* dC Carriage return delay */ +#define NLdelay TCNUM(dN) /* dN Newline delay */ +#define TAdelay TCNUM(dT) /* dT Tab delay */ +#define lines TCNUM(li) /* li Number of lines on screen */ + + +/* Things defined to look more like TERMINFO */ +#define over_strike 0 +#define bell 0 diff --git a/contrib/supdup/terminfo.text b/contrib/supdup/terminfo.text new file mode 100644 index 0000000..7f0ec1b --- /dev/null +++ b/contrib/supdup/terminfo.text @@ -0,0 +1,1010 @@ + NAME + terminfo - terminal capability data base + + SYNOPSIS + /usr/lib/terminfo/?/* + + DESCRIPTION + Terminfo is a data base describing terminals used by, for + example, vi(1) and curses(3X). Terminals are described in + terminfo by giving a set of capabilities which they have, + and by describing how operations are performed. Padding + requirements and initialization sequences are included in + terminfo. + + Entries in terminfo consist of a number of `,' separated + fields. White space after each `,' is ignored. The first + entry for each terminal gives the names which are known for + the terminal, separated by `|' characters. The first name + given is the most common abbreviation for the terminal, the + last name given should be a long name fully identifying the + terminal, and all others are understood as synonyms for the + terminal name. All names but the last should be in lower + case and contain no blanks; the last name may well contain + upper case and blanks for readability. + + Terminal names (except for the last, verbose entry) should + be chosen using the following conventions. The particular + piece of hardware making up the terminal should have a root + name chosen, thus ``hp2621''. This name should not contain + hyphens, except that synonyms may be chosen that do not + conflict with other names. Modes that the hardware can be + in, or user preferences, should be indicated by appending a + hyphen and an indicator of the mode. Thus, a vt100 in 132 + column mode would be vt100-w. The following suffixes should + be used where possible: + Suffix Meaning Example + -w Wide mode (more than 80 columns) vt100-w + -am With auto. margins (usually default) vt100-am + -nam Without automatic margins vt100-nam + -n Number of lines on the screen aaa-60 + -na No arrow keys (leave them in local) c100-na + -np Number of pages of memory c100-4p + -rv Reverse video c100-rv + + CAPABILITIES + The variable is the name by which the programmer (at the + terminfo level) accesses the capability. The capname is the + short name used in the text of the database, and is used by + a person updating the database. The i.code is the two + letter internal code used in the compiled database, and + always corresponds to the old termcap capability name. + + Capability names have no hard length limit, but an informal + limit of 5 characters has been adopted to keep them short + and to allow the tabs in the source file caps to line up + nicely. Whenever possible, names are chosen to be the same + as or similar to the ANSI X3.64-1979 standard. Semantics + are also intended to match those of the specification. + + (P) indicates that padding may be specified + + (G) indicates that the string is passed through tparm with + parms as given (#i). + + (*) indicates that padding may be based on the number of + lines affected + + (# ) indicates the ith parameter. + i + Variable Cap- I. Description + Booleans name Code + auto_left_margin, bw bw cub1 wraps from column 0 to last + column + auto_right_margin, am am Terminal has automatic margins + beehive_glitch, xsb xb Beehive (f1=escape, f2=ctrl C) + ceol_standout_glitch, xhp xs Standout not erased by overwriting + (hp) + eat_newline_glitch, xenl xn newline ignored after 80 cols + (Concept) + erase_overstrike, eo eo Can erase overstrikes with a blank + generic_type, gn gn Generic line type (e.g.,, dialup, + switch). + hard_copy, hc hc Hardcopy terminal + has_meta_key, km km Has a meta key (shift, sets parity + bit) + has_status_line, hs hs Has extra "status line" + insert_null_glitch, in in Insert mode distinguishes nulls + memory_above, da da Display may be retained above the + screen + memory_below, db db Display may be retained below the + screen + move_insert_mode, mir mi Safe to move while in insert mode + move_standout_mode, msgr ms Safe to move in standout modes + over_strike, os os Terminal overstrikes + status_line_esc_ok, eslok es Escape can be used on the status line + teleray_glitch, xt xt Tabs ruin, magic so char (Teleray + 1061) + tilde_glitch, hz hz Hazeltine; can not print ~'s + transparent_underline, ul ul underline character overstrikes + xon_xoff, xon xo Terminal uses xon/xoff handshaking + + Numbers: + columns, cols co Number of columns in a line + + init_tabs, it it Tabs initially every # spaces + lines, lines li Number of lines on screen or page + lines_of_memory, lm lm Lines of memory if > lines. 0 means + varies + magic_cookie_glitch, xmc sg Number of blank chars left by smso or + rmso + padding_baud_rate, pb pb Lowest baud where cr/nl padding is + needed + virtual_terminal, vt vt Virtual terminal number (HP-UX system) + width_status_line, wsl ws No. columns in status line + + Strings: + back_tab, cbt bt Back tab (P) + bell, bel bl Audible signal (bell) (P) + carriage_return, cr cr Carriage return (P*) + change_scroll_region, csr cs change to lines #1 through #2 (vt100) + (PG) + clear_all_tabs, tbc ct Clear all tab stops (P) + clear_screen, clear cl Clear screen and home cursor (P*) + clr_eol, el ce Clear to end of line (P) + clr_eos, ed cd Clear to end of display (P*) + column_address, hpa ch Set cursor column (PG) + command_character, cmdch CC Term. settable cmd char in prototype + cursor_address, cup cm Screen rel. cursor motion row #1 + col #2 (PG) + cursor_down, cud1 do Down one line + cursor_home, home ho Home cursor (if no cup) + cursor_invisible, civis vi Make cursor invisible + cursor_left, cub1 le Move cursor left one space + cursor_mem_address, mrcup CM Memory relative cursor addressing + cursor_normal, cnorm ve Make cursor appear normal (undo vs/vi) + cursor_right, cuf1 nd Non-destructive space (cursor right) + cursor_to_ll, ll ll Last line, first column (if no cup) + cursor_up, cuu1 up Upline (cursor up) + cursor_visible, cvvis vs Make cursor very visible + delete_character, dch1 dc Delete character (P*) + delete_line, dl1 dl Delete line (P*) + dis_status_line, dsl ds Disable status line + down_half_line, hd hd Half-line down (forward 1/2 linefeed) + enter_alt_charset_mode, smacs as Start alternate character set (P) + enter_blink_mode, blink mb Turn on blinking + enter_bold_mode, bold md Turn on bold (extra bright) mode + enter_ca_mode, smcup ti String to begin programs that use cup + enter_delete_mode, smdc dm Delete mode (enter) + enter_dim_mode, dim mh Turn on half-bright mode + enter_insert_mode, smir im Insert mode (enter); + enter_protected_mode, prot mp Turn on protected mode + enter_reverse_mode, rev mr Turn on reverse video mode + enter_secure_mode, invis mk Turn on blank mode (chars invisible) + enter_standout_mode, smso so Begin stand out mode + enter_underline_mode, smul us Start underscore mode + + erase_chars ech ec Erase #1 characters (PG) + exit_alt_charset_mode, rmacs ae End alternate character set (P) + exit_attribute_mode, sgr0 me Turn off all attributes + exit_ca_mode, rmcup te String to end programs that use cup + exit_delete_mode, rmdc ed End delete mode + exit_insert_mode, rmir ei End insert mode + exit_standout_mode, rmso se End stand out mode + exit_underline_mode, rmul ue End underscore mode + flash_screen, flash vb Visible bell (may not move cursor) + form_feed, ff ff Hardcopy terminal page eject (P*) + from_status_line, fsl fs Return from status line + init_1string, is1 i1 Terminal initialization string + init_2string, is2 i2 Terminal initialization string + init_3string, is3 i3 Terminal initialization string + init_file, if if Name of file containing is + insert_character, ich1 ic Insert character (P) + insert_line, il1 al Add new blank line (P*) + insert_padding, ip ip Insert pad after character inserted + (p*) + key_backspace, kbs kb Sent by backspace key + key_catab, ktbc ka Sent by clear-all-tabs key + key_clear, kclr kC Sent by clear screen or erase key + key_ctab, kctab kt Sent by clear-tab key + key_dc, kdch1 kD Sent by delete character key + key_dl, kdl1 kL Sent by delete line key + key_down, kcud1 kd Sent by terminal down arrow key + key_eic, krmir kM Sent by rmir or smir in insert mode + key_eol, kel kE Sent by clear-to-end-of-line key + key_eos, ked kS Sent by clear-to-end-of-screen key + key_f0, kf0 k0 Sent by function key f0 + key_f1, kf1 k1 Sent by function key f1 + key_f10, kf10 ka Sent by function key f10 + key_f2, kf2 k2 Sent by function key f2 + key_f3, kf3 k3 Sent by function key f3 + key_f4, kf4 k4 Sent by function key f4 + key_f5, kf5 k5 Sent by function key f5 + key_f6, kf6 k6 Sent by function key f6 + key_f7, kf7 k7 Sent by function key f7 + key_f8, kf8 k8 Sent by function key f8 + key_f9, kf9 k9 Sent by function key f9 + key_home, khome kh Sent by home key + key_ic, kich1 kI Sent by ins char/enter ins mode key + key_il, kil1 kA Sent by insert line + key_left, kcub1 kl Sent by terminal left arrow key + key_ll, kll kH Sent by home-down key + key_npage, knp kN Sent by next-page key + key_ppage, kpp kP Sent by previous-page key + key_right, kcuf1 kr Sent by terminal right arrow key + key_sf, kind kF Sent by scroll-forward/down key + key_sr, kri kR Sent by scroll-backward/up key + key_stab, khts kT Sent by set-tab key + + key_up, kcuu1 ku Sent by terminal up arrow key + keypad_local, rmkx ke Out of "keypad transmit" mode + keypad_xmit, smkx ks Put terminal in "keypad transmit" mode + lab_f0, lf0 l0 Labels on function key f0 if not f0 + lab_f1, lf1 l1 Labels on function key f1 if not f1 + lab_f10, lf10 la Labels on function key f10 if not f10 + lab_f2, lf2 l2 Labels on function key f2 if not f2 + lab_f3, lf3 l3 Labels on function key f3 if not f3 + lab_f4, lf4 l4 Labels on function key f4 if not f4 + lab_f5, lf5 l5 Labels on function key f5 if not f5 + lab_f6, lf6 l6 Labels on function key f6 if not f6 + lab_f7, lf7 l7 Labels on function key f7 if not f7 + lab_f8, lf8 l8 Labels on function key f8 if not f8 + lab_f9, lf9 l9 Labels on function key f9 if not f9 + memory_lock, meml ml Lock memory above cursor + memory_unlock, memu mu Turn memory lock off + meta_on, smm mm Turn on "meta mode" (8th bit) + meta_off, rmm mo Turn off "meta mode" + newline, nel nw Newline (behaves like cr followed + by lf) + pad_char, pad pc Pad character (rather than null) + parm_dch, dch DC Delete #1 chars (PG*) + parm_delete_line, dl DL Delete #1 lines (PG*) + parm_down_cursor, cud DO Move cursor down #1 lines (PG*) + parm_ich, ich IC Insert #1 blank chars (PG*) + parm_index, indn SF Scroll forward #1 lines (PG) + parm_insert_line, il AL Add #1 new blank lines (PG*) + parm_left_cursor, cub LE Move cursor left #1 spaces (PG) + parm_right_cursor, cuf RI Move cursor right #1 spaces (PG*) + parm_rindex, rin SR Scroll backward #1 lines (PG) + parm_up_cursor, cuu UP Move cursor up #1 lines (PG*) + pkey_key, pfkey pk Prog funct key #1 to type string #2 + pkey_local, pfloc pl Prog funct key #1 to execute string #2 + pkey_xmit, pfx px Prog funct key #1 to xmit string #2 + print_screen, mc0 ps Print contents of the screen + prtr_off, mc4 pf Turn off the printer + prtr_on, mc5 po Turn on the printer + repeat_char, rep rp Repeat char #1 #2 times. (PG*) + reset_1string, rs1 r1 Reset terminal completely to sane modes. + reset_2string, rs2 r2 Reset terminal completely to sane modes. + reset_3string, rs3 r3 Reset terminal completely to sane modes. + reset_file, rf rf Name of file containing reset string + restore_cursor, rc rc Restore cursor to position of last sc + row_address, vpa cv Vertical position absolute + (set row) (PG) + save_cursor, sc sc Save cursor position (P) + scroll_forward, ind sf Scroll text up (P) + scroll_reverse, ri sr Scroll text down (P) + set_attributes, sgr sa Define the video attributes (PG9) + set_tab, hts st Set a tab in all rows, current column + set_window, wind wi Current window is lines #1-#2 + + cols #3-#4 + tab, ht ta Tab to next 8 space hardware tab stop + to_status_line, tsl ts Go to status line, column #1 + underline_char, uc uc Underscore one char and move past it + up_half_line, hu hu Half-line up (reverse 1/2 linefeed) + init_prog, iprog iP Path name of program for init + key_a1, ka1 K1 Upper left of keypad + key_a3, ka3 K3 Upper right of keypad + key_b2, kb2 K2 Center of keypad + key_c1, kc1 K4 Lower left of keypad + key_c3, kc3 K5 Lower right of keypad + prtr_non, mc5p pO Turn on the printer for #1 bytes + + A Sample Entry + + The following entry, which describes the Concept-100, is + among the more complex entries in the terminfo file as of + this writing. + + concept100|c100|concept|c104|c100-4p|concept 100, + am, bel=^G, blank=\EH, blink=\EC, clear=^L$<2*>, cnorm=\Ew, + cols#80, cr=^M$<9>, cub1=^H, cud1=^J, cuf1=\E=, + cup=\Ea%p1%' '%+%c%p2%' '%+%c, + cuu1=\E;, cvvis=\EW, db, dch1=\E^A$<16*>, dim=\EE, dl1=\E^B$<3*>, + ed=\E^C$<16*>, el=\E^U$<16>, eo, flash=\Ek$<20>\EK, ht=\t$<8>, + il1=\E^R$<3*>, in, ind=^J, .ind=^J$<9>, ip=$<16*>, + is2=\EU\Ef\E7\E5\E8\El\ENH\EK\E\200\Eo&\200\Eo\47\E, + kbs=^h, kcub1=\E>, kcud1=\E<, kcuf1=\E=, kcuu1=\E;, + kf1=\E5, kf2=\E6, kf3=\E7, khome=\E?, + lines#24, mir, pb#9600, prot=\EI, rep=\Er%p1%c%p2%' '%+%c$<.2*>, + rev=\ED, rmcup=\Ev $<6>\Ep\r\n, rmir=\E\200, rmkx=\Ex, + rmso=\Ed\Ee, rmul=\Eg, rmul=\Eg, sgr0=\EN\200, + smcup=\EU\Ev 8p\Ep\r, smir=\E^P, smkx=\EX, smso=\EE\ED, + smul=\EG, tabs, ul, vt#8, xenl, + + Entries may continue onto multiple lines by placing white + space at the beginning of each line except the first. + Comments may be included on lines beginning with ``#''. + Capabilities in terminfo are of three types: Boolean + capabilities which indicate that the terminal has some + particular feature, numeric capabilities giving the size of + the terminal or the size of particular delays, and string + capabilities, which give a sequence which can be used to + perform particular terminal operations. + + Types of Capabilities + + All capabilities have names. For instance, the fact that + the Concept has automatic margins (i.e., an automatic return + and linefeed when the end of a line is reached) is indicated + by the capability am. Hence the description of the Concept + + includes am. Numeric capabilities are followed by the + character `#' and then the value. Thus cols, which + indicates the number of columns the terminal has, gives the + value `80' for the Concept. + + Finally, string valued capabilities, such as el (clear to + end of line sequence) are given by the two-character code, + an `=', and then a string ending at the next following `,'. + A delay in milliseconds may appear anywhere in such a + capability, enclosed in $<..> brackets, as in el=\EK$<3>, + and padding characters are supplied by tputs to provide this + delay. The delay can be either a number, e.g., `20', or a + number followed by an `*', i.e., `3*'. A `*' indicates that + the padding required is proportional to the number of lines + affected by the operation, and the amount given is the per- + affected-unit padding required. (In the case of insert + character, the factor is still the number of lines affected. + This is always one unless the terminal has xenl and the + software uses it.) When a `*' is specified, it is sometimes + useful to give a delay of the form `3.5' to specify a delay + per unit to tenths of milliseconds. (Only one decimal place + is allowed.) + + A number of escape sequences are provided in the string + valued capabilities for easy encoding of characters there. + Both \E and \e map to an ESCAPE character, ^x maps to a + control-x for any appropriate x, and the sequences \n \l \r + \t \b \f \s give a newline, linefeed, return, tab, + backspace, formfeed, and space. Other escapes include \^ + for ^, \\ for \, \, for comma, \: for :, and \0 for null. + (\0 will produce \200, which does not terminate a string but + behaves as a null character on most terminals.) Finally, + characters may be given as three octal digits after a \. + + Sometimes individual capabilities must be commented out. To + do this, put a period before the capability name. For + example, see the second ind in the example above. + + Preparing Descriptions + + We now outline how to prepare descriptions of terminals. + The most effective way to prepare a terminal description is + by imitating the description of a similar terminal in + terminfo and to build up a description gradually, using + partial descriptions with vi to check that they are correct. + Be aware that a very unusual terminal may expose + deficiencies in the ability of the terminfo file to describe + it or bugs in vi. To easily test a new terminal description + you can set the environment variable TERMINFO to a pathname + of a directory containing the compiled description you are + working on and programs will look there rather than in + + /usr/lib/terminfo. To get the padding for insert line right + (if the terminal manufacturer did not document it) a severe + test is to edit /etc/passwd at 9600 baud, delete 16 or so + lines from the middle of the screen, then hit the `u' key + several times quickly. If the terminal messes up, more + padding is usually needed. A similar test can be used for + insert character. + + Basic Capabilities + + The number of columns on each line for the terminal is given + by the cols numeric capability. If the terminal is a CRT, + then the number of lines on the screen is given by the lines + capability. If the terminal wraps around to the beginning + of the next line when it reaches the right margin, then it + should have the am capability. If the terminal can clear + its screen, leaving the cursor in the home position, then + this is given by the clear string capability. If the + terminal overstrikes (rather than clearing a position when a + character is struck over) then it should have the os + capability. If the terminal is a printing terminal, with no + soft copy unit, give it both hc and os. (os applies to + storage scope terminals, such as TEKTRONIX 4010 series, as + well as hard copy and APL terminals.) If there is a code to + move the cursor to the left edge of the current row, give + this as cr. (Normally this will be carriage return, control + M.) If there is a code to produce an audible signal (bell, + beep, etc) give this as bel. + + If there is a code to move the cursor one position to the + left (such as backspace) that capability should be given as + cub1. Similarly, codes to move to the right, up, and down + should be given as cuf1, cuu1, and cud1. These local cursor + motions should not alter the text they pass over, for + example, you would not normally use `cuf1= ' because the + space would erase the character moved over. + + A very important point here is that the local cursor motions + encoded in terminfo are undefined at the left and top edges + of a CRT terminal. Programs should never attempt to + backspace around the left edge, unless bw is given, and + never attempt to go up locally off the top. In order to + scroll text up, a program will go to the bottom left corner + of the screen and send the ind (index) string. + + To scroll text down, a program goes to the top left corner + of the screen and sends the ri (reverse index) string. The + strings ind and ri are undefined when not on their + respective corners of the screen. + + Parameterized versions of the scrolling sequences are indn + + and rin which have the same semantics as ind and ri except + that they take one parameter, and scroll that many lines. + They are also undefined except at the appropriate edge of + the screen. + + The am capability tells whether the cursor sticks at the + right edge of the screen when text is output, but this does + not necessarily apply to a cuf1 from the last column. The + only local motion which is defined from the left edge is if + bw is given, then a cub1 from the left edge will move to the + right edge of the previous row. If bw is not given, the + effect is undefined. This is useful for drawing a box + around the edge of the screen, for example. If the terminal + has switch selectable automatic margins, the terminfo file + usually assumes that this is on; i.e., am. If the terminal + has a command which moves to the first column of the next + line, that command can be given as nel (newline). It does + not matter if the command clears the remainder of the + current line, so if the terminal has no cr and lf it may + still be possible to craft a working nel out of one or both + of them. + + These capabilities suffice to describe hardcopy and glass- + tty terminals. Thus the model 33 teletype is described as + + 33|tty33|tty|model 33 teletype, + bel=^G, cols#72, cr=^M, cud1=^J, hc, ind=^J, os, + + while the Lear Siegler ADM-3 is described as + + adm3|3|lsi adm3, + am, bel=^G, clear=^Z, cols#80, cr=^M, cub1=^H, cud1=^J, + ind=^J, lines#24, + + Parameterized Strings + + Cursor addressing and other strings requiring parameters in + the terminal are described by a parameterized string + capability, with printf(3S) like escapes %x in it. For + example, to address the cursor, the cup capability is given, + using two parameters: the row and column to address to. + (Rows and columns are numbered from zero and refer to the + physical screen visible to the user, not to any unseen + memory.) If the terminal has memory relative cursor + addressing, that can be indicated by mrcup. + + The parameter mechanism uses a stack and special % codes to + manipulate it. Typically a sequence will push one of the + parameters onto the stack and then print it in some format. + Often more complex operations are necessary. + + The % encodings have the following meanings: + + %% outputs `%' + %d print pop() as in printf + %2d print pop() like %2d + %3d print pop() like %3d + %02d + %03d as in printf + %c print pop() gives %c + %s print pop() gives %s + + %p[1-9] push ith parm + %P[a-z] set variable [a-z] to pop() + %g[a-z] get variable [a-z] and push it + %'c' char constant c + %{nn} integer constant nn + + %+ %- %* %/ %m + arithmetic (%m is mod): push(pop() op pop()) + %& %| %^ bit operations: push(pop() op pop()) + %= %> %< logical operations: push(pop() op pop()) + %! %~ unary operations push(op pop()) + %i add 1 to first two parms (for ANSI terminals) + + %? expr %t thenpart %e elsepart %; + if-then-else, %e elsepart is optional. + else-if's are possible ala Algol 68: + %? c %t b %e c %t b %e c %t b %e c %t b %e %; + c are conditions, b are bodies. 3 4 4 + i i + Binary operations are in postfix form with the operands in + the usual order. That is, to get x-5 one would use + "%gx%{5}%-". + + Consider the HP2645, which, to get to row 3 and column 12, + needs to be sent \E&a12c03Y padded for 6 milliseconds. Note + that the order of the rows and columns is inverted here, and + that the row and column are printed as two digits. Thus its + cup capability is cup=6\E&%p2%2dc%p1%2dY. + + The Microterm ACT-IV needs the current row and column sent + preceded by a ^T, with the row and column simply encoded in + binary, cup=^T%p1%c%p2%c. Terminals which use %c need to be + able to backspace the cursor (cub1), and to move the cursor + up one line on the screen (cuu1). This is necessary because + it is not always safe to transmit \n ^D and \r, as the + system may change or discard them. (The library routines + dealing with terminfo set tty modes so that tabs are never + expanded, so \t is safe to send. This turns out to be + essential for the Ann Arbor 4080.) + + A final example is the LSI ADM-3a, which uses row and column + offset by a blank character, thus cup=\E=%p1%' '%+%c%p2%' + '%+%c. After sending `\E=', this pushes the first + parameter, pushes the ASCII value for a space (32), adds + them (pushing the sum on the stack in place of the two + previous values) and outputs that value as a character. + Then the same is done for the second parameter. More + complex arithmetic is possible using the stack. + + If the terminal has row or column absolute cursor + addressing, these can be given as single parameter + capabilities hpa (horizontal position absolute) and vpa + (vertical position absolute). Sometimes these are shorter + than the more general two parameter sequence (as with the + hp2645) and can be used in preference to cup . If there are + parameterized local motions (e.g., move n spaces to the + right) these can be given as cud, cub, cuf, and cuu with a + single parameter indicating how many spaces to move. These + are primarily useful if the terminal does not have cup, such + as the TEKTRONIX 4025. + + Cursor Motions + + If the terminal has a fast way to home the cursor (to very + upper left corner of screen) then this can be given as home; + similarly a fast way of getting to the lower left-hand + corner can be given as ll; this may involve going up with + cuu1 from the home position, but a program should never do + this itself (unless ll does) because it can make no + assumption about the effect of moving up from the home + position. Note that the home position is the same as + addressing to (0,0): to the top left corner of the screen, + not of memory. (Thus, the \EH sequence on HP terminals + cannot be used for home.) + + Area Clears + + If the terminal can clear from the current position to the + end of the line, leaving the cursor where it is, this should + be given as el. If the terminal can clear from the current + position to the end of the display, then this should be + given as ed. Ed is only defined from the first column of a + line. (Thus, it can be simulated by a request to delete a + large number of lines, if a true ed is not available.) + + Insert/delete line + + If the terminal can open a new blank line before the line + where the cursor is, this should be given as il1; this is + done only from the first position of a line. The cursor + must then appear on the newly blank line. If the terminal + + can delete the line which the cursor is on, then this should + be given as dl1; this is done only from the first position + on the line to be deleted. Versions of il1 and dl1 which + take a single parameter and insert or delete that many lines + can be given as il and dl. If the terminal has a settable + scrolling region (like the vt100) the command to set this + can be described with the csr capability, which takes two + parameters: the top and bottom lines of the scrolling + region. The cursor position is, alas, undefined after using + this command. It is possible to get the effect of insert or + delete line using this command - the sc and rc (save and + restore cursor) commands are also useful. Inserting lines + at the top or bottom of the screen can also be done using ri + or ind on many terminals without a true insert/delete line, + and is often faster even on terminals with those features. + + If the terminal has the ability to define a window as part + of memory, which all commands affect, it should be given as + the parameterized string wind. The four parameters are the + starting and ending lines in memory and the starting and + ending columns in memory, in that order. + + If the terminal can retain display memory above, then the da + capability should be given; if display memory can be + retained below, then db should be given. These indicate + that deleting a line or scrolling may bring non-blank lines + up from below or that scrolling back with ri may bring down + non-blank lines. + + Insert/Delete Character + + There are two basic kinds of intelligent terminals with + respect to insert/delete character which can be described + using terminfo. The most common insert/delete character + operations affect only the characters on the current line + and shift characters off the end of the line rigidly. Other + terminals, such as the Concept 100 and the Perkin Elmer Owl, + make a distinction between typed and untyped blanks on the + screen, shifting upon an insert or delete only to an untyped + blank on the screen which is either eliminated, or expanded + to two untyped blanks. You can determine the kind of + terminal you have by clearing the screen and then typing + text separated by cursor motions. Type abc def using + local cursor motions (not spaces) between the abc and the + def. Then position the cursor before the abc and put the + terminal in insert mode. If typing characters causes the + rest of the line to shift rigidly and characters to fall off + the end, then your terminal does not distinguish between + blanks and untyped positions. If the abc shifts over to the + def which then move together around the end of the current + line and onto the next as you insert, you have the second + + type of terminal, and should give the capability in, which + stands for insert null. While these are two logically + separate attributes (one line vs. multiline insert mode, and + special treatment of untyped spaces) we have seen no + terminals whose insert mode cannot be described with the + single attribute. + + Terminfo can describe both terminals which have an insert + mode, and terminals which send a simple sequence to open a + blank position on the current line. Give as smir the + sequence to get into insert mode. Give as rmir the sequence + to leave insert mode. Now give as ich1 any sequence needed + to be sent just before sending the character to be inserted. + Most terminals with a true insert mode will not give ich1; + terminals which send a sequence to open a screen position + should give it here. (If your terminal has both, insert + mode is usually preferable to ich1. Do not give both unless + the terminal actually requires both to be used in + combination.) If post insert padding is needed, give this as + a number of milliseconds in ip (a string option). Any other + sequence which may need to be sent after an insert of a + single character may also be given in ip. If your terminal + needs both to be placed into an `insert mode' and a special + code to precede each inserted character, then both smir/rmir + and ich1 can be given, and both will be used. The ich + capability, with one parameter, n, will repeat the effects + of ich1 n times. + + It is occasionally necessary to move around while in insert + mode to delete characters on the same line (e.g., if there + is a tab after the insertion position). If your terminal + allows motion while in insert mode you can give the + capability mir to speed up inserting in this case. Omitting + mir will affect only speed. Some terminals (notably + Datamedia's) must not have mir because of the way their + insert mode works. + + Finally, you can specify dch1 to delete a single character, + dch with one parameter, n, to delete n characters, and + delete mode by giving smdc and rmdc to enter and exit delete + mode (any mode the terminal needs to be placed in for dch1 + to work). + + A command to erase n characters (equivalent to outputting n + blanks without moving the cursor) can be given as ech with + one parameter. + + Highlighting, Underlining, and Visible Bells + + If your terminal has one or more kinds of display + attributes, these can be represented in a number of + + different ways. You should choose one display form as + standout mode, representing a good, high contrast, easy-on- + the-eyes, format for highlighting error messages and other + attention getters. (If you have a choice, reverse video + plus half-bright is good, or reverse video alone.) The + sequences to enter and exit standout mode are given as smso + and rmso, respectively. If the code to change into or out + of standout mode leaves one or even two blank spaces on the + screen, as the TVI 912 and Teleray 1061 do, then xmc should + be given to tell how many spaces are left. + + Codes to begin underlining and end underlining can be given + as smul and rmul respectively. If the terminal has a code + to underline the current character and move the cursor one + space to the right, such as the Microterm Mime, this can be + given as uc. + + Other capabilities to enter various highlighting modes + include blink (blinking) bold (bold or extra bright) dim + (dim or half-bright) invis (blanking or invisible text) prot + (protected) rev (reverse video) sgr0 (turn off all attribute + modes) smacs (enter alternate character set mode) and rmacs + (exit alternate character set mode). Turning on any of + these modes singly may or may not turn off other modes. + + If there is a sequence to set arbitrary combinations of + modes, this should be given as sgr (set attributes), taking + 9 parameters. Each parameter is either 0 or 1, as the + corresponding attribute is on or off. The 9 parameters are, + in order: standout, underline, reverse, blink, dim, bold, + blank, protect, alternate character set. Not all modes need + be supported by sgr, only those for which corresponding + separate attribute commands exist. + + Terminals with the ``magic cookie'' glitch (xmc) deposit + special ``cookies'' when they receive mode-setting + sequences, which affect the display algorithm rather than + having extra bits for each character. Some terminals, such + as the HP 2621, automatically leave standout mode when they + move to a new line or the cursor is addressed. Programs + using standout mode should exit standout mode before moving + the cursor or sending a newline, unless the msgr capability, + asserting that it is safe to move in standout mode, is + present. + + If the terminal has a way of flashing the screen to indicate + an error quietly (a bell replacement) then this can be given + as flash; it must not move the cursor. + + If the cursor needs to be made more visible than normal when + it is not on the bottom line (to make, for example, a non- + + blinking underline into an easier to find block or blinking + underline) give this sequence as cvvis. If there is a way + to make the cursor completely invisible, give that as civis. + The capability cnorm should be given which undoes the + effects of both of these modes. + + If the terminal needs to be in a special mode when running a + program that uses these capabilities, the codes to enter and + exit this mode can be given as smcup and rmcup. This + arises, for example, from terminals like the Concept with + more than one page of memory. If the terminal has only + memory relative cursor addressing and not screen relative + cursor addressing, a one screen-sized window must be fixed + into the terminal for cursor addressing to work properly. + This is also used for the TEKTRONIX 4025, where smcup sets + the command character to be the one used by terminfo. + + If your terminal correctly generates underlined characters + (with no special codes needed) even though it does not + overstrike, then you should give the capability ul. If + overstrikes are erasable with a blank, then this should be + indicated by giving eo. + + Keypad + + If the terminal has a keypad that transmits codes when the + keys are pressed, this information can be given. Note that + it is not possible to handle terminals where the keypad only + works in local (this applies, for example, to the unshifted + HP 2621 keys). If the keypad can be set to transmit or not + transmit, give these codes as smkx and rmkx. Otherwise the + keypad is assumed to always transmit. The codes sent by the + left arrow, right arrow, up arrow, down arrow, and home keys + can be given as kcub1, kcuf1, kcuu1, kcud1, and khome + respectively. If there are function keys such as f0, f1, + ..., f10, the codes they send can be given as kf0, kf1, ..., + kf10. If these keys have labels other than the default f0 + through f10, the labels can be given as lf0, lf1, ..., lf10. + The codes transmitted by certain other special keys can be + given: kll (home down), kbs (backspace), ktbc (clear all + tabs), kctab (clear the tab stop in this column), kclr + (clear screen or erase key), kdch1 (delete character), kdl1 + (delete line), krmir (exit insert mode), kel (clear to end + of line), ked (clear to end of screen), kich1 (insert + character or enter insert mode), kil1 (insert line), knp + (next page), kpp (previous page), kind (scroll + forward/down), kri (scroll backward/up), khts (set a tab + stop in this column). In addition, if the keypad has a 3 by + 3 array of keys including the four arrow keys, the other + five keys can be given as ka1, ka3, kb2, kc1, and kc3. + These keys are useful when the effects of a 3 by 3 + + directional pad are needed. + + Tabs and Initialization + + If the terminal has hardware tabs, the command to advance to + the next tab stop can be given as ht (usually control I). A + ``backtab'' command which moves leftward to the next tab + stop can be given as cbt. By convention, if the teletype + modes indicate that tabs are being expanded by the computer + rather than being sent to the terminal, programs should not + use ht or cbt even if they are present, since the user may + not have the tab stops properly set. If the terminal has + hardware tabs which are initially set every n spaces when + the terminal is powered up, the numeric parameter it is + given, showing the number of spaces the tabs are set to. + This is normally used by the tset command to determine + whether to set the mode for hardware tab expansion, and + whether to set the tab stops. If the terminal has tab stops + that can be saved in nonvolatile memory, the terminfo + description can assume that they are properly set. + + Other capabilities include is1, is2, and is3, initialization + strings for the terminal, iprog, the path name of a program + to be run to initialize the terminal, and if, the name of a + file containing long initialization strings. These strings + are expected to set the terminal into modes consistent with + the rest of the terminfo description. They are normally + sent to the terminal, by the tset program, each time the + user logs in. They will be printed in the following order: + is1; is2; setting tabs using tbc and hts; if; running the + program iprog; and finally is3. Most initialization is done + with is2. Special terminal modes can be set up without + duplicating strings by putting the common sequences in is2 + and special cases in is1 and is3. A pair of sequences that + does a harder reset from a totally unknown state can be + analogously given as rs1, rs2, rf, and rs3, analogous to is2 + and if. These strings are output by the reset program, + which is used when the terminal gets into a wedged state. + Commands are normally placed in rs2 and rf only if they + produce annoying effects on the screen and are not necessary + when logging in. For example, the command to set the vt100 + into 80-column mode would normally be part of is2, but it + causes an annoying glitch of the screen and is not normally + needed since the terminal is usually already in 80 column + mode. + + If there are commands to set and clear tab stops, they can + be given as tbc (clear all tab stops) and hts (set a tab + stop in the current column of every row). If a more complex + sequence is needed to set the tabs than can be described by + this, the sequence can be placed in is2 or if. + + Delays + + Certain capabilities control padding in the teletype driver. + These are primarily needed by hard copy terminals, and are + used by the tset program to set teletype modes + appropriately. Delays embedded in the capabilities cr, ind, + cub1, ff, and tab will cause the appropriate delay bits to + be set in the teletype driver. If pb (padding baud rate) is + given, these values can be ignored at baud rates below the + value of pb. + + Miscellaneous + + If the terminal requires other than a null (zero) character + as a pad, then this can be given as pad. Only the first + character of the pad string is used. + + If the terminal has an extra ``status line'' that is not + normally used by software, this fact can be indicated. If + the status line is viewed as an extra line below the bottom + line, into which one can cursor address normally (such as + the Heathkit h19's 25th line, or the 24th line of a vt100 + which is set to a 23-line scrolling region), the capability + hs should be given. Special strings to go to the beginning + of the status line and to return from the status line can be + given as tsl and fsl. (fsl must leave the cursor position + in the same place it was before tsl. If necessary, the sc + and rc strings can be included in tsl and fsl to get this + effect.) The parameter tsl takes one parameter, which is the + column number of the status line the cursor is to be moved + to. If escape sequences and other special commands, such as + tab, work while in the status line, the flag eslok can be + given. A string which turns off the status line (or + otherwise erases its contents) should be given as dsl. If + the terminal has commands to save and restore the position + of the cursor, give them as sc and rc. The status line is + normally assumed to be the same width as the rest of the + screen, e.g., cols. If the status line is a different width + (possibly because the terminal does not allow an entire line + to be loaded) the width, in columns, can be indicated with + the numeric parameter wsl. + + If the terminal can move up or down half a line, this can be + indicated with hu (half-line up) and hd (half-line down). + This is primarily useful for superscripts and subscripts on + hardcopy terminals. If a hardcopy terminal can eject to the + next page (form feed), give this as ff (usually control L). + + If there is a command to repeat a given character a given + number of times (to save time transmitting a large number of + identical characters) this can be indicated with the + + parameterized string rep. The first parameter is the + character to be repeated and the second is the number of + times to repeat it. Thus, tparm(repeat_char, 'x', 10) is + the same as `xxxxxxxxxx'. + + If the terminal has a settable command character, such as + the TEKTRONIX 4025, this can be indicated with cmdch. A + prototype command character is chosen which is used in all + capabilities. This character is given in the cmdch + capability to identify it. The following convention is + supported on some HP-UX systems: The environment is to be + searched for a CC variable, and if found, all occurrences of + the prototype character are replaced with the character in + the environment variable. + + Terminal descriptions that do not represent a specific kind + of known terminal, such as switch, dialup, patch, and + network, should include the gn (generic) capability so that + programs can complain that they do not know how to talk to + the terminal. (This capability does not apply to virtual + terminal descriptions for which the escape sequences are + known.) + + If the terminal uses xon/xoff handshaking for flow control, + give xon. Padding information should still be included so + that routines can make better decisions about costs, but + actual pad characters will not be transmitted. + + If the terminal has a ``meta key'' which acts as a shift + key, setting the 8th bit of any character transmitted, this + fact can be indicated with km. Otherwise, software will + assume that the 8th bit is parity and it will usually be + cleared. If strings exist to turn this ``meta mode'' on and + off, they can be given as smm and rmm. + + If the terminal has more lines of memory than will fit on + the screen at once, the number of lines of memory can be + indicated with lm. A value of lm#0 indicates that the + number of lines is not fixed, but that there is still more + memory than fits on the screen. + + If the terminal is one of those supported by the HP-UX + virtual terminal protocol, the terminal number can be given + as vt. + + Media copy strings, which control an auxiliary printer + connected to the terminal, can be given as mc0: print the + contents of the screen, mc4: turn off the printer, and mc5: + turn on the printer. When the printer is on, all text sent + to the terminal will be sent to the printer. It is + undefined whether the text is also displayed on the terminal + + screen when the printer is on. A variation mc5p takes one + parameter, and leaves the printer on for as many characters + as the value of the parameter, then turns the printer off. + The parameter should not exceed 255. All text, including + mc4, is transparently passed to the printer while an mc5p is + in effect. + + Strings to program function keys can be given as pfkey, + pfloc, and pfx. Each of these strings takes two parameters: + the function key number to program (from 0 to 10) and the + string to program it with. Function key numbers out of this + range may program undefined keys in a terminal dependent + manner. The difference between the capabilities is that + pfkey causes pressing the given key to be the same as the + user typing the given string; pfloc causes the string to be + executed by the terminal in local; and pfx causes the string + to be transmitted to the computer. + + Glitches + + Hazeltine terminals, which do not allow `~' characters to be + displayed should indicate hz. + + Terminals which ignore a linefeed immediately after an am + wrap, such as the Concept and vt100, should indicate xenl. + + If el is required to get rid of standout (instead of merely + writing normal text on top of it), xhp should be given. + + Teleray terminals, where tabs turn all characters moved over + to blanks, should indicate xt (destructive tabs). This + glitch is also taken to mean that it is not possible to + position the cursor on top of a ``magic cookie'', that to + erase standout mode it is instead necessary to use delete + and insert line. + + The Beehive Superbee, which is unable to correctly transmit + the escape or control C characters, has xsb, indicating that + the f1 key is used for escape and f2 for control C. (Only + certain Superbees have this problem, depending on the ROM.) + + Other specific terminal problems may be corrected by adding + more capabilities of the form xx. + + Similar Terminals + + If there are two very similar terminals, one can be defined + as being just like the other with certain exceptions. The + string capability use can be given with the name of the + similar terminal. The capabilities given before use + override those in the terminal type invoked by use. A + + capability can be cancelled by placing xx@ to the left of + the capability definition, where xx is the capability. For + example, the entry + + 2621-nl, smkx@, rmkx@, use=2621, + + defines a 2621-nl that does not have the smkx or rmkx + capabilities, and hence does not turn on the function key + labels when in visual mode. This is useful for different + modes for a terminal, or for different user preferences. + + WARNINGS + HP only supports terminals listed on the current list of + supported devices. However, non-supported and supported + terminals can be in the terminfo database. If you use such + non-supported terminals, they may not work correctly. + + FILES + /usr/lib/terminfo/?/* files containing terminal + descriptions + + SEE ALSO + tic(1M), untic(1M), curses(3X), printf(3S), term(4). + diff --git a/contrib/supdup/tsd.tc b/contrib/supdup/tsd.tc new file mode 100644 index 0000000..1e0a1e8 --- /dev/null +++ b/contrib/supdup/tsd.tc @@ -0,0 +1 @@ +setenv TERMCAP 'SD|supdup|SUPDUP virtual terminal:co#79:li#48:am:vb=\177\023:nd=\177\020:cl=\177\022:so=\177\031:se=\177\032:pt:ce=\177\005:ec=\177\006:cd=\177\004:bs:up=\177\041:cm=\177\021%+ %+ :nl=\177\014:al=\177\025\001:dl=\177\026\001:AL=\177\025%.:DL=\177\026%.:mi:im=:ei=:ic=\177\027\001:dc=\177\030\001:dm=:ed=:ns:km:' diff --git a/run/dfkfb/README b/run/dfkfb/README new file mode 100644 index 0000000..0893eea --- /dev/null +++ b/run/dfkfb/README @@ -0,0 +1,6 @@ +The following file is derived from Digital software and subject to +Digital licensing requirements: + + dfkfb-all.savh (DFKFB diagnostic) + +For usage and KL data, see the documentation file "doc/dfkfb.txt". diff --git a/run/dfkfb/dfkfb-all.savh b/run/dfkfb/dfkfb-all.savh new file mode 100644 index 0000000..60249ff Binary files /dev/null and b/run/dfkfb/dfkfb-all.savh differ diff --git a/run/dfkfb/dfkfb.ini b/run/dfkfb/dfkfb.ini new file mode 100644 index 0000000..4ae82d1 --- /dev/null +++ b/run/dfkfb/dfkfb.ini @@ -0,0 +1,19 @@ +; KLH10 init file for +; DFKFB - KL10 timing test diagnostic +; Normal load requires DIAMON+SUBKL+DFKFB but all of these are +; already combined in dfkfb-all.savh. + +devdef dte0 200 dte master +; Make sure clock is at rate DFKFB expects +set clk_ithzfix=60 + +set ld_fmt=h36 +load dfkfb-all.savh +set sw=400100,,0 + +; Hi-ho, hi-ho +go + +; Quit when done +quit + diff --git a/run/klnic/README b/run/klnic/README new file mode 100644 index 0000000..a132335 --- /dev/null +++ b/run/klnic/README @@ -0,0 +1,6 @@ +The following files are derived from Digital software and subject to +Digital licensing requirements: + + boot-nic.sav (disk bootstrap) + mtboot-nic.sav (tape bootstrap) + diff --git a/run/klnic/boot-nic.sav b/run/klnic/boot-nic.sav new file mode 100644 index 0000000..41deb7f Binary files /dev/null and b/run/klnic/boot-nic.sav differ diff --git a/run/klnic/dist-klnic.ini b/run/klnic/dist-klnic.ini new file mode 100644 index 0000000..efb6376 --- /dev/null +++ b/run/klnic/dist-klnic.ini @@ -0,0 +1,21 @@ +; This file is KLH10.INI -- the KLH10 init file that is read and executed +; by default when the KLH10 starts up. + +; Define basic device config - one DTE, one disk, one tape +devdef dte0 200 dte master +devdef rh0 540 rh20 +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 path=NICDIST-RP06-0.dbd9 dpdma=on +devdef mta0 rh0.1 tm03 fmtr=tm03 type=tu45 + +; Add one more disk for use as KLH: +devdef rh1 544 rh20 +;devdef dsk1 rh1.0 rp type=rp06 format=dbd9 path=KLH-RP06.dbd9 + +; Define KLNI with address that monitor expects +devdef ni0 564 ni20 ipaddr=192.168.0.251 + +; Define new HOST device hackery +devdef idler 700 host + +; Load disk bootstrap for convenience +load boot-nic.sav diff --git a/run/klnic/dist51-klnic.ini b/run/klnic/dist51-klnic.ini new file mode 100644 index 0000000..e8e69f6 --- /dev/null +++ b/run/klnic/dist51-klnic.ini @@ -0,0 +1,21 @@ +; This file is KLH10.INI -- the KLH10 init file that is read and executed +; by default when the KLH10 starts up. + +; Define basic device config - one DTE, one disk, one tape +devdef dte0 200 dte master +devdef rh0 540 rh20 +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 path=NICDIST-RP06-0.dbd9 dpdma=on +devdef mta0 rh0.1 tm03 fmtr=tm03 type=tu45 + +; Add one more disk for use as KLH: +devdef rh1 544 rh20 +;devdef dsk1 rh1.0 rp type=rp06 format=dbd9 path=KLH-RP06.dbd9 + +; Define KLNI with address that monitor expects +devdef ni0 564 ni20 ipaddr=10.0.0.51 + +; Define new HOST device hackery +devdef idler 700 host + +; Load disk bootstrap for convenience +load boot-nic.sav diff --git a/run/klnic/klh10.ini b/run/klnic/klh10.ini new file mode 100644 index 0000000..db0ec6c --- /dev/null +++ b/run/klnic/klh10.ini @@ -0,0 +1,21 @@ +; This file is KLH10.INI -- the KLH10 init file that is read and executed +; by default when the KLH10 starts up. + +; Define basic device config - one DTE, one disk, one tape +devdef dte0 200 dte master +devdef rh0 540 rh20 +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 path=RP06-NIC-0.dbd9 dpdma=on +devdef mta0 rh0.1 tm03 fmtr=tm03 type=tu45 + +; Add one more disk for use as KLH: +devdef rh1 544 rh20 +devdef dsk1 rh1.0 rp type=rp06 format=dbd9 path=RP06-KLH.dbd9 + +; Define KLNI with address that monitor expects +devdef ni0 564 ni20 ipaddr=192.168.0.251 + +; Define new HOST device hackery +devdef idler 700 host + +; Load disk bootstrap for convenience +load boot-nic.sav diff --git a/run/klnic/mtboot-nic.sav b/run/klnic/mtboot-nic.sav new file mode 100644 index 0000000..6f3305d Binary files /dev/null and b/run/klnic/mtboot-nic.sav differ diff --git a/run/klt10/README b/run/klt10/README new file mode 100644 index 0000000..5489842 --- /dev/null +++ b/run/klt10/README @@ -0,0 +1,6 @@ +The following files are derived from Digital software and subject to +Digital licensing requirements: + + klbddt.exe (bootstrap with DDT) + klboot.exe (disk/tape bootstrap) + diff --git a/run/klt10/klbddt.exe b/run/klt10/klbddt.exe new file mode 100644 index 0000000..fc71eb3 Binary files /dev/null and b/run/klt10/klbddt.exe differ diff --git a/run/klt10/klboot.exe b/run/klt10/klboot.exe new file mode 100644 index 0000000..d0928be Binary files /dev/null and b/run/klt10/klboot.exe differ diff --git a/run/klt10/klt10.ini b/run/klt10/klt10.ini new file mode 100644 index 0000000..396a9b6 --- /dev/null +++ b/run/klt10/klt10.ini @@ -0,0 +1,18 @@ +; Sample KLH10.INI for initial installation + +; Define basic device config - one DTE, one disk, one tape. +; Use two RH20s because TOPS-10 doesn't like mixing disk and tape on +; the same controller (TOPS-20 is fine). + +; T10 needs DTE ACK delay +devdef dte0 200 dte master ackdly=5 +devdef rh0 540 rh20 +devdef rh1 544 rh20 +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 +devdef mta0 rh1.0 tm03 type=tu77 + +; For DECNET if desired +; +devdef ni0 564 ni20 dedic=0 decnet=1 doarp=0 enaddr=aa:00:04:00:ac:60 dpdelay=12 c3dly=2 rdtmo=3 + +load klboot.exe diff --git a/run/klt20/README b/run/klt20/README new file mode 100644 index 0000000..8042c89 --- /dev/null +++ b/run/klt20/README @@ -0,0 +1,5 @@ +The following files are derived from Digital software and subject to +Digital licensing requirements: + + boot.sav (disk bootstrap) + mtboot.sav (tape bootstrap) diff --git a/run/klt20/boot.sav b/run/klt20/boot.sav new file mode 100644 index 0000000..e455655 Binary files /dev/null and b/run/klt20/boot.sav differ diff --git a/run/klt20/inst-klt20.ini b/run/klt20/inst-klt20.ini new file mode 100644 index 0000000..59ec10e --- /dev/null +++ b/run/klt20/inst-klt20.ini @@ -0,0 +1,23 @@ +; Sample KLH10.INI for initial installation + +; Define basic device config - one DTE, one disk, one tape. +; Use two RH20s because TOPS-10 doesn't like mixing disk and tape on +; the same controller (TOPS-20 is fine). + +devdef dte0 200 dte master +devdef rh0 540 rh20 +devdef rh1 544 rh20 +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 +devdef mta0 rh1.0 tm03 type=tu45 + +; Need KLNI to avoid LAPRBF BUGCHKs - use valid address if known +; +devdef ni0 564 ni20 ipaddr=10.0.0.51 + +; Mount installation tape (no ucode or boot to skip) +devmount mta0 bb-h137f-bm.tap + +; Load tape bootstrap directly +load mtboot.sav + +; Now ready to GO diff --git a/run/klt20/klt20.ini b/run/klt20/klt20.ini new file mode 100644 index 0000000..ad66100 --- /dev/null +++ b/run/klt20/klt20.ini @@ -0,0 +1,20 @@ +; Sample KLH10.INI for initial installation + +; Define basic device config - one DTE, one disk, one tape. +; Use two RH20s because TOPS-10 doesn't like mixing disk and tape on +; the same controller (TOPS-20 is fine). + +devdef dte0 200 dte master +devdef rh0 540 rh20 +devdef rh1 544 rh20 +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 +devdef mta0 rh1.0 tm03 type=tu45 + +; Need KLNI to avoid LAPRBF BUGCHKs - use valid address if known +; +devdef ni0 564 ni20 ipaddr=10.0.0.51 + +; Load disk bootstrap directly +load boot.sav + +; Now ready to GO diff --git a/run/klt20/mtboot.sav b/run/klt20/mtboot.sav new file mode 100644 index 0000000..3fbcf71 Binary files /dev/null and b/run/klt20/mtboot.sav differ diff --git a/run/ksits/@.ddt-u b/run/ksits/@.ddt-u new file mode 100644 index 0000000..7a1c2f7 Binary files /dev/null and b/run/ksits/@.ddt-u differ diff --git a/run/ksits/@.its-647kn-u b/run/ksits/@.its-647kn-u new file mode 100644 index 0000000..37f425b Binary files /dev/null and b/run/ksits/@.its-647kn-u differ diff --git a/run/ksits/@.its-647md-u b/run/ksits/@.its-647md-u new file mode 100644 index 0000000..4d34744 Binary files /dev/null and b/run/ksits/@.its-647md-u differ diff --git a/run/ksits/@.its-647pi-u b/run/ksits/@.its-647pi-u new file mode 100644 index 0000000..eaf7f81 Binary files /dev/null and b/run/ksits/@.its-647pi-u differ diff --git a/run/ksits/@.nsalv-260-u b/run/ksits/@.nsalv-260-u new file mode 100644 index 0000000..856bbcc Binary files /dev/null and b/run/ksits/@.nsalv-260-u differ diff --git a/run/ksits/README b/run/ksits/README new file mode 100644 index 0000000..5046de2 --- /dev/null +++ b/run/ksits/README @@ -0,0 +1,18 @@ +The following files are derived from MIT ITS software and subject to +their licensing requirements: + + @.ddt-u (DDT standalone) + @.nsalv-260-u (NSALV standalone) + @.its-647pi-u (PI ITS monitor bootstrap) + @.its-647kn-u (KN ITS monitor bootstrap) + @.its-647md-u (MD ITS monitor bootstrap) + itsbin.647pi-u (PI ITS alone, no DDT or SALV) + itsbin.647kn-u (KN ITS alone, no DDT or SALV) + itsbin.647md-u (MD ITS alone, no DDT or SALV) + +The "pubits" directory contains various notes left over from the +Public ITS project. One file in particular has been updated: + + pubits/doc/distrib.its - various notes on bringing up a new ITS + +Read it! diff --git a/run/ksits/itsbin.647kn-u b/run/ksits/itsbin.647kn-u new file mode 100644 index 0000000..d6e61df Binary files /dev/null and b/run/ksits/itsbin.647kn-u differ diff --git a/run/ksits/itsbin.647md-u b/run/ksits/itsbin.647md-u new file mode 100644 index 0000000..42397a2 Binary files /dev/null and b/run/ksits/itsbin.647md-u differ diff --git a/run/ksits/itsbin.647pi-u b/run/ksits/itsbin.647pi-u new file mode 100644 index 0000000..bc14c00 Binary files /dev/null and b/run/ksits/itsbin.647pi-u differ diff --git a/run/ksits/klh10-kn.ini b/run/ksits/klh10-kn.ini new file mode 100644 index 0000000..63f8060 --- /dev/null +++ b/run/ksits/klh10-kn.ini @@ -0,0 +1,31 @@ +; KLH10 emulator configuration for KN ITS system. + +; Define basic KS10 device config - two RH11s each on its own Unibus + +devdef rh0 ub1 rh11 addr=776700 br=6 vec=254 +devdef rh1 ub3 rh11 addr=772440 br=6 vec=224 + +; Provide one disk, one tape in config ITS expects + +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 path=PI-ITS-RP06.0-dbd9 iodly=0 +devdef mta0 rh1.0 tm02 fmtr=tm03 type=tu45 + +; ITS wants a 60Hz clock, allow it. Need this until defaults OK. +set clk_ithzfix=60 + +; Define IMP for MD +devdef imp ub3 lhdh addr=767600 br=6 vec=250 ipaddr=10.134.198.236 gwaddr=10.0.0.1 + +; Dummy definitions. Only one DZ is still (apparently) needed. +devdef dz0 ub3 dz11 addr=760010 br=5 vec=340 +;devdef dz1 ub3 dz11 addr=760020 br=5 vec=350 +;devdef chaos ub3 ch11 addr=764140 br=5 vec=270 + +; Define new HOST device hackery +devdef idler ub3 host addr=777000 + +; Preload ITS for convenience +load @.its-647kn-u + +; Use "GO 774000" to start DDT, else just "GO" to start ITS + diff --git a/run/ksits/klh10-md.ini b/run/ksits/klh10-md.ini new file mode 100644 index 0000000..dea4b79 --- /dev/null +++ b/run/ksits/klh10-md.ini @@ -0,0 +1,31 @@ +; KLH10 emulator configuration for MD ITS system. + +; Define basic KS10 device config - two RH11s each on its own Unibus + +devdef rh0 ub1 rh11 addr=776700 br=6 vec=254 +devdef rh1 ub3 rh11 addr=772440 br=6 vec=224 + +; Provide one disk, one tape in config ITS expects + +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 path=PI-ITS-RP06.0-dbd9 iodly=0 +devdef mta0 rh1.0 tm02 fmtr=tm03 type=tu45 + +; ITS wants a 60Hz clock, allow it. Need this until defaults OK. +set clk_ithzfix=60 + +; Define IMP for MD +devdef imp ub3 lhdh addr=767600 br=6 vec=250 ipaddr=192.168.0.203 gwaddr=192.168.0.2 + +; Dummy definitions. Only one DZ is still (apparently) needed. +devdef dz0 ub3 dz11 addr=760010 br=5 vec=340 +;devdef dz1 ub3 dz11 addr=760020 br=5 vec=350 +;devdef chaos ub3 ch11 addr=764140 br=5 vec=270 + +; Define new HOST device hackery +devdef idler ub3 host addr=777000 + +; Preload ITS for convenience +load @.its-647md-u + +; go 774000 ; to start DDT, else "go" to start ITS + diff --git a/run/ksits/klh10-pi.ini b/run/ksits/klh10-pi.ini new file mode 100644 index 0000000..bcafdb3 --- /dev/null +++ b/run/ksits/klh10-pi.ini @@ -0,0 +1,31 @@ +; KLH10 emulator configuration for PI ITS system. + +; Define basic KS10 device config - two RH11s each on its own Unibus + +devdef rh0 ub1 rh11 addr=776700 br=6 vec=254 +devdef rh1 ub3 rh11 addr=772440 br=6 vec=224 + +; Provide one disk, one tape in config ITS expects + +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 path=PI-ITS-RP06.0-dbd9 iodly=0 +devdef mta0 rh1.0 tm02 fmtr=tm03 type=tu45 + +; ITS wants a 60Hz clock, allow it. Need this until defaults OK. +set clk_ithzfix=60 + +; Define IMP for PI on ITS.JOSS.COM +devdef imp ub3 lhdh addr=767600 br=6 vec=250 ipaddr=199.34.53.51 gwaddr=199.34.53.50 + +; Dummy definitions. Only one DZ is still (apparently) needed. +devdef dz0 ub3 dz11 addr=760010 br=5 vec=340 +;devdef dz1 ub3 dz11 addr=760020 br=5 vec=350 +;devdef chaos ub3 ch11 addr=764140 br=5 vec=270 + +; Define new HOST device hackery +devdef idler ub3 host addr=777000 + +; Preload ITS for convenience +load @.its-647pi-u + +; go 774000 ; to start DDT, else "go" to start ITS + diff --git a/run/ksits/pubits/adm/hosts.its b/run/ksits/pubits/adm/hosts.its new file mode 100644 index 0000000..97fd072 --- /dev/null +++ b/run/ksits/pubits/adm/hosts.its @@ -0,0 +1,21 @@ + +# Per RFC 1918, there are 3 IP address space blocks assigned for private nets, +# which will never (and can never) be used on the external Internet: +# 10.0.0.0 - 10.255.255.255 (10/8 prefix) 1 class A net +# 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) 16 class B nets +# 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) 256 class C nets +# +# IP conventions: +# 0 and 255 reserved for broadcast (IP standard) + +# Addresses for setup of Public ITS in Doug Humphrey's co-location facility. +# Reserved 8-address block from 199.34.53.48-55 inclusive. +# .48 # Old bcast +# .49 # Router/Gateway +199.34.53.50 its.joss.com its # Native system +199.34.53.51 pi.its.os.org pi # Public ITS (virtual) +199.34.53.52 dx.its.os.org dx # Digex ITS (virtual) +199.34.53.53 du.its.os.org du # Hack ITS (virtual) +199.34.53.54 unknown.its.os.org # Reserved +# .55 # Subnet broadcast + diff --git a/run/ksits/pubits/adm/its.ipfw b/run/ksits/pubits/adm/its.ipfw new file mode 100644 index 0000000..85be9e5 --- /dev/null +++ b/run/ksits/pubits/adm/its.ipfw @@ -0,0 +1,188 @@ +#!/bin/sh - + +# Paranoid ipfw configuration for its.os.org box + +[ -f /etc/rc.conf ] && . /etc/rc.conf +ipfw="/sbin/ipfw" +[ "x$firewall_quiet" = "xYES" ] && ipfw="$ipfw -q" + +#### configure #### + +# 199.34.53.48/29 +# 255.255.255.248 +# .48 +# 199.34.53.49 +# 199.34.53.50 its.joss.com (NATIVE SYSTEM) +# 199.34.53.51 pi.its.os.org (VIRTUAL ITS) +# 199.34.53.52 dx.its.os.org (VIRTUAL ITS) +# 199.34.53.53 du.its.os.org (VIRTUAL ITS) +# 199.34.53.54 ??.its.os.org (VIRTUAL ITS) +# .55 +# + +# Addresses. "me" is its.joss.com +# +us=199.34.53.48/29 +b0=199.34.53.48 +gw=199.34.53.49 +me=199.34.53.50 +pi=199.34.53.51 +dx=199.34.53.52 +du=199.34.53.53 +qq=199.34.53.54 +b1=199.34.53.55 + +# Name of our interface to the outside world (ethernet, presumably) +# +if=de0 + +################### + +# Clean slate +# +$ipfw -f flush + +# Do not accept source routed traffic under any circumstances +# +$ipfw add deny log all from any to any ipoptions ssrr,lsrr,rr + +# Allow everything on loopback interface +# +$ipfw add pass all from any to any via lo0 + +## IP rules ## + +# Loopback addresses on non-loopback interfaces are spoofed +# +$ipfw add deny log all from any to 127.0.0.0/8 +$ipfw add deny log all from 127.0.0.0/8 to any + +# As far as I know there is no reason for any traffic to or from +# any kind of broadcast, class D, class E, or RFC-1597 private +# address to appear on this subnet. +# +# Tuez les tous, Dieu reconnaitra les siens. +# +$ipfw add deny log all from $b0 to any +$ipfw add deny log all from $b1 to any +$ipfw add deny log all from 0.0.0.0 to any +$ipfw add deny log all from 224.0.0.0/3 to any +$ipfw add deny log all from 255.255.255.255 to any +$ipfw add deny log all from any to $b0 +$ipfw add deny log all from any to $b1 +$ipfw add deny log all from any to 0.0.0.0 +$ipfw add deny log all from any to 224.0.0.0/3 +$ipfw add deny log all from any to 255.255.255.255 +$ipfw add deny log all from 10.0.0.0/8 to any +$ipfw add deny log all from 172.16.0.0/12 to any +$ipfw add deny log all from 192.168.0.0/16 to any +$ipfw add deny log all from any to 10.0.0.0/8 +$ipfw add deny log all from any to 172.16.0.0/12 +$ipfw add deny log all from any to 192.168.0.0/16 + +# Don't let anybody else pretend to be this unix machine +# +$ipfw add deny log all from $me to any in recv any + +# If anybody actually figures out how to hack ITS into spoofing, we +# probably ought to sign that person up on the spot, but just in case +# some total loser gets lucky, let's make it a little harder for +# spoofed packets to escape from ITS +# Note: this also prevents a misconfigured ITS from causing trouble. +# +$ipfw add deny log all from not $us to any in recv 'tun*' +$ipfw add deny log all from $gw to any in recv 'tun*' + +# Last, a little protection in case our first-hop router isn't checking +# addresses as carefully as we are +# +$ipfw add deny log all from any to not $us in recv $if +$ipfw add deny log all from $pi to any in recv $if +$ipfw add deny log all from $dx to any in recv $if +$ipfw add deny log all from $du to any in recv $if +$ipfw add deny log all from $qq to any in recv $if + +# Add any other rules to discard known bogus addresses here + +## TCP rules + +# We do our TCP connection checking on setup, so just let +# any established connection go through +# Most TCP traffic matches this rule, so put it as early as possible +# +$ipfw add pass tcp from any to any established + +# Allow TELNET and FTP into the ITS machines +# Don't allow TELNET or FTP to the unix machine +# ITS doesn't support PASV FTP, so neither do we +# +$ipfw add reset log tcp from any to $me telnet,ftp setup +$ipfw add pass tcp from any to any telnet,ftp setup + +# Allow SSH & SMTP into the unix box +# +$ipfw add pass tcp from any to $me ssh,smtp setup + +# Any connection initiated by the unix machine is ok +# +$ipfw add pass tcp from $me to any setup + +# Don't allow any other connections to the unix machine +# +$ipfw add reset log from any to $me setup + +# ITS machines are not allowed to initiate connections to the outside world +# Anything else coming from an ITS machine is ok +# +$ipfw add reset log tcp from any to any setup out recv 'tun*' xmit $if +$ipfw add pass tcp from any to any setup recv 'tun*' + +# Silently drop IDENT traffic +# (Gee, Dr. Bernstein, let's launch a denial-of-service attack on ourselves!) +# +$ipfw add reset tcp from any to any ident setup + +# No other TCP connections allowed +# +$ipfw add reset log tcp from any to any setup + +# Please don't even think about turning on SunRPC or NFS +# +$ipfw add deny log udp from any to any sunrpc,nfs + +# Don't accept inbound syslog from the outside world +# (no known useful purpose, so don't let bozos fill our log directory) +# +$ipfw add deny log udp from any to any syslog in recv $if + +# We need DNS and NTP +# +$ipfw add pass udp from any dns,ntp to any +$ipfw add pass udp from any to any dns,ntp + +# Allow useful cases of syslog. Heck, maybe ITS should use it +# +$ipfw add pass udp from $us to $us syslog + +# Allow the useful ICMP messages: +# Echo (types 0 & 8, for ping and traceroute) +# Destination Unreachable (type 3) +# Time Exceeded (type 11, primarily for traceroute) +# +# We should NOT accept ICMP Redirects (we're a router) +$ipfw add pass icmp from any to any icmptypes 0,3,8,11 +$ipfw add deny icmp from any to any out recv $if xmit 'tun*' +$ipfw add pass icmp from any to any out xmit 'tun*' + +# Silently discard ICMP Router Discovery strobes +# +$ipfw add deny icmp from any to any icmptypes 10 + +# Deny and log everything else. If this turns out to be too +# verbose, consider adding rules to silently drop stuff that +# we understand but don't want. Anything we don't understand +# probably ought to be logged. +# +# If you don't understand it, it's dangerous. +# +$ipfw add deny log all from any to any diff --git a/run/ksits/pubits/adm/rc.firewall-its b/run/ksits/pubits/adm/rc.firewall-its new file mode 100644 index 0000000..331ed57 --- /dev/null +++ b/run/ksits/pubits/adm/rc.firewall-its @@ -0,0 +1,211 @@ +#!/bin/sh - +## Paranoid ipfw configuration for its.os.org box + +# Suck in the configuration variables. +if [ -f /etc/defaults/rc.conf ]; then + . /etc/defaults/rc.conf +elif [ -f /etc/rc.conf ]; then + . /etc/rc.conf +fi + +############ +# Set quiet mode if requested +if [ "x$firewall_quiet" = "xYES" ]; then + fwcmd="/sbin/ipfw -q" +else + fwcmd="/sbin/ipfw" +fi + +#### configure #### + +# 199.34.53.48/29 +# 255.255.255.248 +# .48 +# 199.34.53.49 +# 199.34.53.50 its.joss.com (NATIVE SYSTEM) +# 199.34.53.51 pi.its.os.org (VIRTUAL ITS) +# 199.34.53.52 dx.its.os.org (VIRTUAL ITS) +# 199.34.53.53 du.its.os.org (VIRTUAL ITS) +# 199.34.53.54 ??.its.os.org (VIRTUAL ITS) +# .55 +# + +# Addresses. "me" is its.joss.com +# +us=199.34.53.48/29 +b0=199.34.53.48 +gw=199.34.53.49 +me=199.34.53.50 +pi=199.34.53.51 +dx=199.34.53.52 +du=199.34.53.53 +qq=199.34.53.54 +b1=199.34.53.55 + +# Name of our interface to the outside world (ethernet, presumably) +# +oif=de0 + +################### + +# Clean slate +# +$fwcmd -f flush + +# Do not accept source routed traffic under any circumstances +# +$fwcmd add deny log all from any to any ipoptions ssrr,lsrr,rr + +# Allow everything on loopback interface +# +$fwcmd add pass all from any to any via lo0 + +## IP rules ## + +# Loopback addresses on non-loopback interfaces are spoofed +# +$fwcmd add deny log all from any to 127.0.0.0/8 +$fwcmd add deny log all from 127.0.0.0/8 to any + +# As far as I know there is no reason for any traffic to or from +# any kind of broadcast, class D, class E, or RFC-1597 private +# address to appear on this subnet. +# +# Tuez les tous, Dieu reconnaitra les siens. +# +$fwcmd add deny log all from $b0 to any +$fwcmd add deny log all from $b1 to any +$fwcmd add deny log all from 0.0.0.0 to any +$fwcmd add deny log all from 224.0.0.0/3 to any +$fwcmd add deny log all from 255.255.255.255 to any +$fwcmd add deny log all from any to $b0 +$fwcmd add deny log all from any to $b1 +$fwcmd add deny log all from any to 0.0.0.0 +$fwcmd add deny log all from any to 224.0.0.0/3 +$fwcmd add deny log all from any to 255.255.255.255 +$fwcmd add deny log all from 10.0.0.0/8 to any +$fwcmd add deny log all from 172.16.0.0/12 to any +#KLH $fwcmd add deny log all from 192.168.0.0/16 to any +$fwcmd add deny log all from any to 10.0.0.0/8 +$fwcmd add deny log all from any to 172.16.0.0/12 +#KLH $fwcmd add deny log all from any to 192.168.0.0/16 + +# Don't let anybody else pretend to be this unix machine +# +$fwcmd add deny log all from $me to any in recv any + +# If anybody actually figures out how to hack ITS into spoofing, we +# probably ought to sign that person up on the spot, but just in case +# some total loser gets lucky, let's make it a little harder for +# spoofed packets to escape from ITS +# Note: this also prevents a misconfigured ITS from causing trouble. +# +$fwcmd add deny log all from not $us to any in recv 'tun*' +$fwcmd add deny log all from $gw to any in recv 'tun*' + +# Last, a little protection in case our first-hop router isn't checking +# addresses as carefully as we are. Prohibit any packets coming into +# the interface which are from our own subnet, except for ICMPs from +# the gateway. +$fwcmd add pass icmp from $gw to $us recv $oif icmptypes 0,3,8,11 +$fwcmd add deny log all from $us to any in recv $oif +$fwcmd add deny log all from any to not $us in recv $oif + +# Add any other rules to discard known bogus addresses here + +## TCP rules + +# We do our TCP connection checking on setup, so just let +# any established connection go through +# Most TCP traffic matches this rule, so put it as early as possible +# +$fwcmd add pass tcp from any to any established + +##################### +# The intent of the following rules is: +# The only way to access the Unix system from outside is via SSH, +# and later SMTP after mailer is configured. +# The only outside access to PI ITS is via TELNET/SUPDUP. +# (Later FTP? Note ITS doesn't support PASV FTP.) +# Nothing from outside to DU/DX (the dev ITS systems). Access has +# to be via SSH to unix and thence to DU/DX. +# PI cannot go anywhere, either outside or locally. +# Unix and DU/DX can go anywhere, both outside & locally. + + +# Access from outside - permit only these things +# Allow TELNET/SUPDUP into PI ITS. +# Allow SSH into the unix box. Add SMTP later after mailer is configured. +# +$fwcmd add pass tcp from any to $pi telnet,supdup setup +$fwcmd add pass tcp from any to $me ssh setup + +# Any connection initiated by the unix machine or DU, DX is okay. +# All three have full access to all systems plus outside world. +# +$fwcmd add pass tcp from $me to any setup +$fwcmd add pass tcp from $dx to any setup +$fwcmd add pass tcp from $du to any setup + +# Don't allow any other connections. +# +$fwcmd add reset log tcp from any to any setup + +# For possible later use: +# ITS machines are not allowed to initiate connections to the outside world +# Anything else coming from an ITS machine is ok +# +# $fwcmd add reset log tcp from any to any setup out recv 'tun*' xmit $oif +# $fwcmd add pass tcp from any to any setup recv 'tun*' + +# KLH: what's the point of this when the next rule refuses it anyway? +# Silently drop IDENT traffic +# (Gee, Dr. Bernstein, let's launch a denial-of-service attack on ourselves!) +# +$fwcmd add reset tcp from any to any ident setup + +# No other TCP connections allowed +# +$fwcmd add reset log tcp from any to any setup + +# Please don't even think about turning on SunRPC or NFS +# +$fwcmd add deny log udp from any to any sunrpc,nfs + +# Don't accept inbound syslog from the outside world +# (no known useful purpose, so don't let bozos fill our log directory) +# +$fwcmd add deny log udp from any to any syslog in recv $oif + +# We need DNS (domain) and NTP +# +$fwcmd add pass udp from any domain,ntp to any +$fwcmd add pass udp from any to any domain,ntp + +# Allow useful cases of syslog. Heck, maybe ITS should use it +# +$fwcmd add pass udp from $us to $us syslog + +# Allow the useful ICMP messages: +# Echo (types 0 & 8, for ping and traceroute) +# Destination Unreachable (type 3) +# Time Exceeded (type 11, primarily for traceroute) +# +# We should NOT accept ICMP Redirects (we're a router) +$fwcmd add pass icmp from any to any icmptypes 0,3,8,11 +$fwcmd add deny icmp from any to any out recv $oif xmit 'tun*' +$fwcmd add pass icmp from any to any out xmit 'tun*' + +# Silently discard ICMP Router Discovery strobes +# +$fwcmd add deny icmp from any to any icmptypes 10 + +# Deny and log everything else. If this turns out to be too +# verbose, consider adding rules to silently drop stuff that +# we understand but don't want. Anything we don't understand +# probably ought to be logged. +# +# If you don't understand it, it's dangerous. +# +$fwcmd add deny log all from any to any + diff --git a/run/ksits/pubits/adm/router.notes b/run/ksits/pubits/adm/router.notes new file mode 100644 index 0000000..3e60b48 --- /dev/null +++ b/run/ksits/pubits/adm/router.notes @@ -0,0 +1,9 @@ + +In order to test PI ITS configured for its future home, need to +add explicit routing table entries: + +On ITS.JOSS.COM: + # route add -net 192.168.0.0 -interface 199.34.53.50 + +On other machines: + # route add -net 199.34.53.0 -interface 192.168.0.xx (own address) diff --git a/run/ksits/pubits/doc/bootload.files b/run/ksits/pubits/doc/bootload.files new file mode 100644 index 0000000..ad410d3 --- /dev/null +++ b/run/ksits/pubits/doc/bootload.files @@ -0,0 +1,132 @@ +NX . +FREE BLOCKS #0=24927 + 0 . LOGIN 1 ! 4/5/77 14:11:08 + 0 @ AI-ITS 59 ! 12/17/92 17:04:48 + 0 @ DDT 4 ! 5/31/89 04:59:14 + 0 @ ITS 63 ! 12/17/92 17:05:37 + 0 @ NSALV 13 ! 12/17/92 17:05:03 + 0 @ SALV38 13 ! 6/4/92 12:32:09 + 0 AIDSKD 212BIN 3 ! 3/30/86 23:36:29 + 0 AIDSKD 212BT 1 ! 3/30/86 23:39:54 + 0 AIITS 644BIN 52 ! 2/26/90 19:46:46 + 0 AIITS 644ERR 1 ! 2/26/90 19:46:46 + 0 AISALV 238ERR 1 ! 6/3/88 02:18:28 + 0 AISALV 253BIN 12 ! 2/26/90 19:37:07 + 0 AISALV 253ERR 1 ! 2/26/90 19:37:07 + 0 AISALV 328BIN 12 ! 6/3/88 02:18:28 + 0 DDT 068BIN 4 ! 7/19/92 13:53:44 + 0 DSKDMP 216BIN 3 ! 7/20/92 04:35:00 + 0 DSKDMP 216BT 1 ! 7/20/92 04:35:16 + 0 ITS 645BIN 53 ! 7/20/92 04:34:15 + 0 NSALV 260BIN 12 ! 7/20/92 04:35:29 + L SALV BIN . NSALV 260BIN + 0 TS REDRCT 3 ! 7/15/87 01:36:25 + +DDT= 774000 Start addr of DDT (DDT data can precede this) +MACDMP= 777700 Loc of bootstrap loader (and start addr) +MACCR= 777777 Loc of ? + + 0 @ AI-ITS 59 ! 12/17/92 17:04:48 + ITSMCH= 'AI' ITSVRS= '1644' 213000(SALV:VERSHN)/ '253' + Has DDT, no bootstrap; start addr is BEG. + This was the last MIT AI KS10 system. + + 0 @ DDT 4 ! 5/31/89 04:59:14 + Assembled by ALAN on 05/31/89 05:00:12 + Assembled from file AI: SYSTEM; DDT 68 + + 0 @ ITS 63 ! 12/17/92 17:05:37 + ITSMCH= 'NX' ITSVRS= '1645' 213000(SALV:VERSHN)/ '260' + Has DDT, no bootstrap; start addr is BEG. + + 0 @ NSALV 13 ! 12/17/92 17:05:03 + VERSHN/ '260' + Has DDT, no bootstrap; start addr is DDT + + 0 @ SALV38 13 ! 6/4/92 12:32:09 + VERSHN/ '238' + Has DDT, no bootstrap; start addr is DDT + Assembled from SYSTEM;SALV 238, retained just in case NSALV + someday encounters a bug that SALV doesn't have. + + 0 AIDSKD 212BIN 3 ! 3/30/86 23:36:29 + Assembled by ALAN on 03/30/86 23:37:03 + Assembled from file AI: SYSTEM; DSKDMP 212 + Retained for backup and posterity. Doesn't work on KLH10 due to + I/O race bug. + + 0 AIDSKD 212BT 1 ! 3/30/86 23:39:54 + Assembled by ALAN on 03/30/86 23:40:20 + Assembled from file AI: SYSTEM; DSKDMP 212 + Retained for backup and posterity. + + 0 AIITS 644BIN 52 ! 2/26/90 19:46:46 + Assembled by ALAN5 on 02/26/90 19:59:44 + Assembled from file AI: SYSTEM; ITS 1644 + Last MIT AI KS10 system. + 0 AIITS 644ERR 1 ! 2/26/90 19:46:46 + + 0 AISALV 238ERR 1 ! 6/3/88 02:18:28 + Retained to document @ SALV38. + + 0 AISALV 253BIN 12 ! 2/26/90 19:37:07 + Assembled by ALAN5 on 02/26/90 19:40:13 + Assembled from file AI: KSHACK; NSALV 253 + AI config, retained for additional backup to NSALV 260. + 0 AISALV 253ERR 1 ! 2/26/90 19:37:07 + + 0 DDT 068BIN 4 ! 7/19/92 13:53:44 + Assembled by KLH on 07/19/92 13:54:01 + Assembled from file AI: SYSTEM; DDT 68 + + 0 DSKDMP 216BIN 3 ! 7/20/92 04:35:00 + Assembled by KLH on 07/20/92 04:35:06 + Assembled from file NX: SYSTEM; DSKDMP 216 + + 0 DSKDMP 216BT 1 ! 7/20/92 04:35:16 + Assembled by KLH on 07/20/92 04:35:20 + Assembled from file NX: SYSTEM; DSKDMP 216 + + 0 ITS 645BIN 53 ! 7/20/92 04:34:15 + Assembled by KLH on 07/20/92 04:33:50 + Assembled from file NX: SYSTEM; ITS 1645 + + 0 NSALV 260BIN 12 ! 7/20/92 04:35:29 + Assembled by KLH on 07/20/92 04:35:57 + Assembled from file NX: KSHACK; NSALV 260 + + 0 TS REDRCT 3 ! 7/15/87 01:36:25 + Assembled by ALAN on 07/15/87 01:36:46 + Assembled from file AI: SYSNET; REDRCT 21 + This is a utility to manage the gateway tables + inside the running system. + +OLD AI snapshot files, version # listed here so as to satisfy +any lingering curiousity about the contents. + +All contain DDT, no DSKDMP bootstrap, and start addr of DDT except for +ITS which starts at BEG. + + 0 @ ODDT 4 ! 1/18/87 13:42:01 + Assembled by MOON on 01/18/87 13:43:13 + Assembled from file AI: SYSTEM; DDT 51 + 0 @ NSALV 13 ! 3/19/89 21:15:01 VERSHN/ '245' + 0 @ OOSALV 13 ! 3/26/86 23:30:01 VERSHN/ '211' + 0 @ OSALV 13 ! 12/1/86 00:00:00 VERSHN/ '229' + 0 @ SALV 13 ! 6/2/88 23:42:15 VERSHN/ '238' + 0 @ XSALV 13 ! 9/1/90 22:53:26 VERSHN/ '215' + 0 @ ITS 58 ! 2/5/90 03:27:50 + ITSMCH= 'AI' ITSVRS= '1643' 213000(SALV:VERSHN)/ '238' + 0 @ NITS 58 ! 2/28/90 13:05:37 + ITSMCH= 'AI' ITSVRS= '1644' 213000(SALV:VERSHN)/ '238' + 0 @ OITS 58 ! 1/25/90 20:45:27 + ITSMCH= 'AI' ITSVRS= '1633' 213000(SALV:VERSHN)/ '238' + 0 @ XITS 55 ! 9/1/90 22:53:22 + ITSMCH= 'MD' ITSVRS= '1576' 213000(SALV:VERSHN)/ '215' + + 0 KSTEST BIN 7 ! 1/22/86 23:49:52 + Assembled by JTW on 01/22/86 23:50:47 + Assembled from file MC: JTW; KSTEST 179 + This is just a standalone hack to allow invoking various + device status or action routines with DDT and $X. + It's not really a diagnostic program. diff --git a/run/ksits/pubits/doc/distrib.its b/run/ksits/pubits/doc/distrib.its new file mode 100644 index 0000000..f5926aa --- /dev/null +++ b/run/ksits/pubits/doc/distrib.its @@ -0,0 +1,823 @@ +ITS distribution notes: + +Lots of random stuff in random order, some old, some new. Most of it +was personal notes to myself, only vaguely intended for publication, +which I never had time to clean up. + +As you read through this stuff, you should be thinking in the back of +your head, "How can we get all this (%*@(%!# crap to work better?" + +Here's one suggestion. + +Ideally there would be a single file containing all of the runtime +site-dependent config stuff (hostname, address, params for various +progs, etc). Can maintain numerous configs in a single directory +called SYSCNF with a link pointing from the default of "@ DEFS" to +to the file actually in effect, which would be SYSCNF; . + +ITS would then check this default file on startup for its identity. +Can also force use of a specific config file by depositing something +with DDT in an otherwize zero location prior to startup (its machname +for example, from which the SYSCNF file can be found). This location +can even be known and set by the KLH10 init file! + + +Notes on system-dependent config stuff: + + If you are generating a NEW instance of ITS with a new name, + there are a lot of things you have to do. Read through this + whole section! + +To rebuild ITS, do: + :MIDAS SYSTEM;_ITS + and then type the desired machine name, in UPPERCASE. + There are a lot of undefined symbols in EVSYMS at the end; + these can be ignored. + + You may want to rename the resulting ITS BIN to ITS , eg + :rename its bin, its 645pi + in order to avoid clobbering it with the next assembly. + +To get a KLH10-loadable executable from that: + Extract it from ITS with either: + [a] FTP it out (use image mode) to a file, eg "itsbin.645pi" + [b] Virtual magtape (copy to MT0:, uses coredump mode) + KLH10: devmount mta0 tapeout rw fmt=raw + ITS: :copy system;its 645pi, mt0: + (If get RH11 ERROR, ignore and try again) + KLH10: devunmount mta0 + Convert to format of choice, normally U36, with one of: + FTP: ./wfconv -fu < itsbin.645pi > itsbin.645pi-u + Tape: ./wfconv -cu < tapeout.tpr > itsbin.645pi-u + In a fresh KLH10, no config needed: + ./kn10-ks /dev/null + load @.ddt-u + load @.nsalv-260-u + load itsbin.645pi-u + dump @.its-645pi-u + quit + Thereafter you can just load @.its-whatever and go. + + +NEW SYSTEM +========== + + Things that must be edited for each new ITS system/machine. + +ITS MACHINE NAME: + Pick a good one. + Historically all ITS machine names have been exactly two characters. + Someday we may have a list of just what things actually depend on + this or some other limit, as well as whether digits are permitted. + @DEV - requires 2 characters for other ITSes. + MLDEV - requires 2 characters for other ITSes. + LISP - requires 3 characters due to CAIE checks. Code could + easily be fixed for 6. + +Build new ITS +------------- + Modify these files and then rebuild ITS per above instructions. + + SET NAME: + The ITS machine name, two characters. + SYSTEM;CONFIG > - define chunk of params for each name. + SYSTEM;ITS > - add to comment at start? Not really needed. + + SET NET ADDRESS: + SYSTEM;CONFIG > + IMPUS3 - the IP address. + NM%IMP - Subnet mask for IMPUS3. + IMPUS - old IMP address. Set it to low-order byte of IMPUS3 + to avoid breaking any old semi-working stuff.. + TTY TABLE: + SYSTEM;TTYTYP > + Machine-name conditionalized; must have machine-specific + entries for hard-wired terminal lines. + + +Build user config files and programs +------------------------------------ + + HOSTNAME: Very important -- COMSAT and other things will break if + they can't find their own system name in the host tables! + + First edit this file to add hostname(s): + SYSHST;H3TEXT > + Although this used to be dynamically generated, it must now + be done by hand. + Then run: + SYSHST;H3MAKE BIN + which snarfs up H3TEXT and compiles it into SYSBIN;HOSTS3 >. + This can take quite a while depending on how large H3TEXT is. + + TELSER: SYSNET;TELSER > + TELSER has hard-coded greeting messages based on hostname. If + it doesn't recognize its own hostname, it uses "Unknown ITS PDP-10". + This can be modified if desired (just before TCPOL:) for hack value. + :MIDAS SYSBIN;_SYSNET;TELSER + + MLDEV: SYSEN2:MLDEV > + There are two places in this program which have a hardcoded list + of ITS machines. The name of the new ITS must be added here + if you wish to use the MLDEV device to access the filesystems + of other machines. + These names must exist in HOSTS3 as it uses NETWRK"HSTLOOK to find + the corresponding IP addresses. + Also set DEVICE;JOBDEV symlinked to DEVICE;ATSIGN MLDEV. + + MLDEV/MLSLV and known job devices in general: + The maximum size of a device name is 6 SIXBIT characters, although + very old programs sometimes assume 3. + Whenever a program uses a device name that ITS doesn't have + built in, the system runs the "unknown device handler" + which is SYS;ATSIGN DEVICE (source SYSENG;@DEV >). + (Note the binary is a SBLK file -- it exists too briefly) + It then processes this device name as follows: + If "<" or ">" - Returns "No such device" error. + If DSK:DEVICE;JOBDEV exists - loads and starts that program. + This overrides all the rest of this stuff and is the + preferable way of configuring things. + Otherwise @DEV goes through a lot of trouble to figure out a plausible + interpretation of the device name, using a semi-built-in table of + known "foreign filesystems" and DIR device names, that it checks to + map the device into one of four possible devices: + DSK:DEVICE;ATSIGN DIRDEV - SYSENG;DIRDEV > + DSK:DEVICE;ATSIGN MLDEV - SYSEN2;MLDEV > + DSK:DEVICE;ATSIGN R.I.P. - SYSEN2;RIPDEV > + DSK:DEVICE;ATSIGN RMTDEV - GZ;RMTDEV > + (All are or should be PDUMPed binaries) + These tables are checked as follows: + If either table contains an exact match, use that. + Else if the first 2 chars of the name match something in the foreign + filesys table (here's one 2-char dependency!), it tries + DEVICE;JOBDEV , then DEVICE;ATSIGN MLDEV. + The foreign system will presumably interpret the rest of + the device name (typically DIR or ARC, etc). + The other table is mostly DIR where is one of + ,DSK,SYS,COM,DIR,DNR. + If there's still no match, it checks for a secondary pack name + using a table of machine names (AI and MX for now) and + a subtable of pack names for each. This seems to be only + for the purpose of returning a "Pack not mounted" error + if the pack is known to normally exist, as opposed to + a "no such device" error. + If still no match, it checks the last letter -- if it's a digit, + it strips it off and starts all over again. + FINALLY, it checks to see whether the request is to open the + directory of a known non-directory device (ie if the + FN1 and FN2 are ".FILE. (DIR)") and cobbles together + a simple reply if so. The known devices for this hack are: + lpt,ptr,ptp,plt,cod,dis,nvd,pdp,tab,stk + + MLDEV, when invoked, checks its real device name and performs + some additional munching. It knows about a list of + ITS systems, and for each in the list: + X is transformed into . + DIR is transformed into DIR (for consistency?) + The 1st 2 chars (another dependency!) are then checked + and if they match a , that system is contacted. + list: AI ML DM MC MX MD KL KS + If there's no match to any of these, then MLDEV tries one + more table before giving up. If the full device name is + one of the following, it substitutes a dev: + XGP => AIXGP + GLP => MXGLP + DVR => MCDVR + DVS => MCDVS + TPL => MLTPL + Otherwise, it returns "no such device". This means no + foreign filesystem can be contacted unless it IS IN + THE HARDWIRED TABLE of MLDEV! + If is known, then it uses NETWRK"HSTLOOK to find the + IP address and proceeds to make a connection. + +OTHER: + Various programs automatically re-init and PDUMP themselves out when + they detect that the machine name or system version has changed + since the last binary was created. Among these are: + SYS;TS NAME + SYS;TS PEEK + SYS;TS PROBE + SYS1;TS METER + SYS1;TS PRUFD + SYS1;TS SYSMSG + SYS2;TS XXFILE + SYSBIN;FIDO BIN + +Other programs that don't automatically repurify themselves, but need to + be invoked properly after assembling: + SYS;TS MIDAS (sblk orig in SYSBIN;MIDAS *BIN, start at PURIFY) + .MAIL.;COMSAT LAUNCH (orig in SYSNET;COMSAT BIN, start at PURIFY) + + +DUMP remembers the name of the machine it was assembled on, and + complains if the current system isn't it. Just rebuild. + This can be bypassed by setting variable WRONG back to zero + after it's started up. + DUMP needs SYSENG;FSDEFS > and SYSNET;NETWRK > to assemble. + DUMP hacks the file SYSENG;MACRO TAPES. + Also hacks .TAPE0; etc?? + +FTPS is patched so it doesn't try (and fail) to look up its own host name. + MAINIT+25/ MOVEI A,[ASCIZ /MIT-NX.US.ORACLE.COM/] ? NOP + + Patched in SYSBIN;FTPS BIN. + Original binary in SYSBIN;FTPS ORGBIN. + + This patch is unnecessary if the NETWRK hostname lookup software + is working (see HOSTS3 below), but the NETHST syscall is buggy + cuz it returns the value of IMPUS, not IMPUS3. Before fixing this, + have to be sure nothing else will break! Sigh! + +SYS;NET MAIL - Telnet/supdup server announcement. + Revised for NX, original in NET OMAIL. + Note: there is a long-standing bug in the TELSER/STY interaction such + that the initial %TDORS for a supdup connection happens halfway through + a longish greeting message (NET MAIL) and wipes the rest out after + the 105th char. Note 23 chars in machine greeting, plus a CRLF + or so, to make 130 chars. This may be STY buffer size? + +SYS;SYSTEM MAIL - universal DDT startup announcement, if any. + Flushed, original in SYSTEM OMAIL. + +SYS;RECORD TIME - Checked & updated to see how long ITS has run. + +Various programs that check machine name specially: + DUMP (as noted above) + SYSEN1;PWORD - has table of per-machine specs + INQUIR;INQUIR - similar check + MACLSP - tries to map predefined atom or something, at UDIRSE. + Checks for AI,ML,MC,MD,MX. + MLDEV - checks for known machines using 2-char assumption. + SYSNET;TELSER - Checks machine name to select greeting header. + SYSEN1;SENDER - Checks machine name to see if sending to a known ITS + or not. (Doesn't bother to use host table to check sys type!) + +ITS edits or patches: + + See also "modlog" which may have more details. + + FIXED in SYSTEM;ITS 1646 + Quantum timer patch: + This is an ITS bug that skews the quantum counter timing. + UTRNTR+2/ LDB A, [ + 125603/ SETZ Q,UPQUAN(U) 044000,,UPQUAN(u) + ] + FIXED in SYSTEM;IMP 367 + NETHST patch: + ANETH2+3/ MOVE B,NIFIPA (from MOVEI B,IMPUS) + + Not a bugfix, just a crude firewall patch: + TCPO4+23/ JRST OPNL6 (from CALL PKTGFI) + (prevents outbound TCP opens) + + + FIXED in SYSTEM;TIME 951 + Y2K patch. Replace: + CLCQDT+2/ + PUSH P,E-1 + PUSH P,E + MOVE E-1,FYEAR + IDIVI E-1,100. + DPB E,[330700,,QDATE] ;YEAR + POP P,E + POP P,E-1 + with: + PUSH P,E + MOVE E,FYEAR + SUBI E,1900. + DPB E,[331000,,QDATE] ;YEAR + POP P,E + +NSALV bug: + This code in NSALV (part of the INIT startup) is sorta buggy + in that when NDRIVE is 1 it is asking for a reverse BLT... + + SETOM DRIVE ;For now, assume all drives on-line. + MOVE A,[DRIVE,,DRIVE+1] + BLT A,DRIVE+NDRIVE-1 + +DSKDMP bug: + I forget where this is but am making a note so I remember to + someday come back and document it. + There is a race condition on booting where DSKDMP initiates a + disk transfer that clobbers the code it is about to execute + next. It works on a real machine because the CPU is much + faster than the disk. + Patched, but not really needed now that KLH10 can load ITS directly. + + +DIRECTORY STATUS +================ + (NNF = No New Files since final AI/MC snapshot) + +OK . - Boot load files. See "bootload.files" for more info. + Most of old AI stuff flushed as useless. +OK .INFO. - NNF, restore all +OK .MAIL. - Empty, must fill for COMSAT (and flush old useless files) +OK .MSGS. - Empty, old msgs all obsolete & discarded. +OK .TAPE0 - Empty is OK; contains some gubbish from KLH dumps. +OK .TECO. - NNF, restore all +OK .TEMP. - NNF, restore all (empty except for a -READ- -THIS- file) + +? C - only partially restored +OK CHANNA - NNF, Restore all +OK CRASH - Empty. Note COMSAT crashes will leave a BURNUP file here, + and each use of CRTSTY adds one line to CRTSTY LOG. +OK DEVICE - NNF, Restore all (but not all are needed) + However, file CHAOS HOST# isn't present in Alan's snapshot. +OK DRAGON - NNF, Restore (but not all are needed; lots of junk!) +OK EMACS - NNF, Restore all +OK GREN - PERSONAL, NX-only. Flushed from distrib. +? HACK - New, retain for NX, not needed for distrib + (but update or remove messages) +OK INFO - NNF, Restore all +OK INQUIR - NNF, Restore all +OK JLV - PERSONAL, NX-only. Flushed from distrib. +OK KLH - PERSONAL, NX-only, but may be a few sources that need + to be included for distrib: OUT,NUUOS,OUTDOC,MACROS. + Move to KSC. + (problem; need to update .INSRTs of other progs?) +OK KSC - NNF, restore all. +? KSHACK - Mostly new files. Perhaps restore others? + Note the DEC ucode source is proprietary; exclude it? +OK LISP - NNF, Restore all (needed for INQUIR, sigh) +OK MAINT - NNF, Restore all + This contains DEC diagnostic binaries but leave it for now. +OK MIDAS - NNF except for bugfix: TSRTNS 234 +OK MRC - PERSONAL, NX-only. Flushed from distrib. +OK SYS - Mostly NNF, restore all. Lots of possibly superfluous + large PURQIO files, ugh. But don't know which progs might + use which of them... +OK SYS1 - NNF, Restore all +OK SYS2 - NNF, Restore all +OK SYS3 - NNF, Restore all +OK SYSBIN - Mostly NNF, restore. Lots of OBINs that could flush. +OK SYSDOC - NNF, restore all +OK SYSEN1 - NNF, restore all +OK SYSEN2 - NNF, restore all +OK SYSENG - NNF, restore all except for MACRO TAPES (site-specific) +OK SYSHST - Mostly NNF, restore all (new versions of H3TEXT). +OK SYSNET - Mostly NNF, restore all (new version of TELSER). +OK SYSTEM - Several new files; should clean out old versions. + +FILE UPDATES AND CHANGES: +======================== + +This list contains all files added or modified since NX first came up +from the original AI/MC snapshot, with descriptive notes. It does NOT +contain links; many links have a creation time postdating this but +they are almost certainly artifacts of the way link restoral was done. + +See "nxmodfiles" for a complete list of all files or links that +postdate the creation of NX. + +NX:C; +NX:CHANNA; +NX:CRASH; + 0 CRTSTY LOG 0 +333 ! 9/24/99 18:46:17 (9/24/99) KLH +NX:DEVICE; +NX:DRAGON; + 0 DRAGON HOARD 4 +90 ! 6/11/92 02:56:32 (15/31/127) -??- + 0 RAKASH PFTHMG 4 +578 ! 6/11/92 02:56:32 (10/23/99) -??- +NX:EMACS; +NX:GREN; + 0 GREN LOGIN 0 +489 ! 7/23/93 18:50:26 (8/17/93) + 0 GREN OSENDS 0 +44 ! 7/23/93 18:55:38 (7/23/93) + 0 GREN PLAN 0 +8 ! 7/29/93 12:10:33 (8/17/93) +NX:HACK; + 0 KLH10 MSG 3 +157 ! 11/8/92 01:46:07 (11/10/92) -??- + 0 KLH10 NEWS 0 +660 ! 5/25/93 15:52:15 (5/25/93) KLH + 0 NX NEWS 0 +275 ! 5/3/93 14:24:31 (7/22/93) KLH +NX:INFO; +NX:INQUIR; +NX:KLH; + 0 COM INFO 0 +229 ! 1/29/93 00:31:09 (5/20/93) + 0 CONFIG 1 7 +1 ! 11/7/92 13:41:12 (9/24/99) -??- + 0 CONFIG 2 7 +1 ! 9/24/99 04:04:03 (9/24/99) + 0 CONFIG 3 6+1016 ! 9/24/99 04:07:38 (9/24/99) + 0 DDT NBIN 3 +458 ! 1/5/93 17:15:15 (5/20/93) + 0 DDT NEW 3 +449 ! 1/5/93 17:08:04 (5/20/93) + 0 DDT TORIG 3 +458 ! 1/5/93 17:08:45 (4/5/93) + 0 FIRST EMACS 0 +3 ! 11/8/92 01:29:21 (10/3/99) + 0 ITS BIN 56 +346 ! 10/28/93 11:35:05 (10/28/93) + 0 KLH MAIL 1 +86 ! 7/23/93 18:45:00 (10/24/99) .MAIL. + 0 KLH10 ARCHIV 0 +866 ! 5/25/93 16:00:15 (10/3/99) .MAIL. + 0 KLH10 PEOPLE 0 +384 ! 8/5/93 12:29:21 (8/23/93) + 0 MAIL FRMHQM 0 +22 ! 11/9/92 20:42:04 (5/20/93) -??- + 0 TEMP FILE 0 +13 ! 7/19/92 10:40:14 (11/8/92) + 0 WALL 1 5 +152 ! 12/23/92 15:09:31 (12/23/92) + 0 WALL 2 0 ! 1/14/93 00:44:45 (1/14/93) + 0 WALL 3 8 +15 ! 1/14/93 00:54:11 (1/14/93) + 0 WALL 4 8 +15 ! 1/14/93 03:41:59 (1/14/93) + 0 WALL 5 0 +133 ! 1/16/93 06:13:50 (1/16/93) + 0 WALL 6 7 +992 ! 1/16/93 06:16:51 (1/16/93) + 0 WALL 7 7 +992 ! 1/16/93 06:43:49 (1/16/93) + 0 XLINKS 1 2 +12 ! 11/8/92 01:20:54 (12/9/92) -??- + 0 _FTPU_ OUTPUT 0 ! 1/28/93 17:58:51 (1/28/93) + +NX:KSC; + TS ZOTZ - New, just a ZOTZ BIN patched for 50K (not 500K) loop count + 0 TS ZOTZ 3 +317 ! 12/16/92 16:51:33 (9/24/99) KLH +NX:KSHACK; + 0 NSALV BIN 11 +437 ! 7/20/92 04:35:29 (7/20/92) KLH + 0 NXBOOT ALLFS 0 +22 ! 1/16/93 06:16:18 (4/9/93) KLH + 0 NXBOOT FILES 0 +42 ! 1/16/93 06:11:07 (4/9/93) KLH +NX:MAINT; + +NX:MIDAS; + 0 TS NMIDAS 22 +357 ! 6/23/92 15:10:28 (4/9/93) -??- + 0 TSRTNS 234 27 +612 ! 6/23/92 17:23:37 (4/9/93) -??- + +NX:MRC; + +NX:SYS; + NET MAIL - Telnet/supdup server announcement. Revised for NX, + original in NET OMAIL. + :MSGS TIMES - Used by DDT's :MSGS command to remember the last + time each user invoked it; data file of uname/datim pairs. + TS MIDAS - New, version 458. Old version (433) renamed to TS OMIDAS. + 0 :MSGS TIMES 4 ! 10/24/99 01:53:05 (10/24/99) KLH + 0 NET MAIL 0 +16 ! 5/3/93 14:28:10 (10/24/99) KLH + 0 RECORD TIME 0 ! 6/19/92 17:19:49 (9/24/99) KLH + 0 TS MIDAS 22 +357 ! 4/9/93 21:36:42 (9/24/99) KLH + 0 TS NAME 16 +108 ! 4/15/93 19:07:13 (10/3/99) KLH + 0 TS PEEK 14 +726 ! 4/7/93 19:03:07 (10/24/99) KLH + 0 TS PROBE 7 +8 ! 7/23/93 18:54:38 (7/23/93) GREN +NX:SYS1; + 0 TS METER 3 +398 ! 5/19/93 19:12:17 (5/20/93) MRC + 0 TS PRUFD 0 +506 ! 4/6/93 17:23:25 (4/6/93) KLH + 0 TS SYSMSG 2 +568 ! 6/7/93 13:04:43 (6/21/93) KLH +NX:SYS2; + 0 TS XXFILE 5 +982 ! 4/5/93 19:59:23 (4/5/93) KLH +NX:SYS3; + +NX:SYSBIN; + FTPS BIN Patched with new IP address; orig is FTPS ORGBIN. + MIDAS 458BIN New version, latest. + 0 FIDO BIN 3 +430 ! 5/11/93 13:39:52 (5/11/93) KLH + 0 FTPS BIN 10 +367 ! 11/7/92 13:40:41 (5/19/93) KLH + 0 HOSTS3 2002 68 +757 ! 5/19/93 12:51:50 (10/24/99) KLH + 0 MIDAS 458BIN 17 +108 ! 4/9/93 21:26:11 (4/9/93) KLH + 0 TELSER BIN 3 +87 ! 5/3/93 13:53:46 (10/24/99) KLH + New version (TELSER 173) with NX greeting. + Old file renamed to TELSER AIBIN. + +NX:SYSDOC; +NX:SYSEN1; +NX:SYSEN2; + +NX:SYSENG; + Must flush this site-specific weirdo; it will conflict with version + from dump! DUMP maintains this as a directory of all macro tapes + written on the system. + 0 MACRO TAPES 40 ! 3/1/93 21:43:22 + 0 MACRO TAPES 39 +64 ! 9/24/99 04:32:12 (9/24/99) KLH + +NX:SYSHST; + New versions of H3TEXT >. + 0 H3TEXT 2000 82 +412 ! 5/17/93 18:36:38 (5/17/93) -??- + 0 H3TEXT 2002 74 +35 ! 5/17/93 19:33:08 (5/19/93) KLH + +NX:SYSNET; + 0 TELSER 173 7 +886 ! 5/3/93 13:53:31 (5/3/93) KLH + New version with NX greeting. + +NX:SYSTEM; + Several new files; should clean out old versions. + 0 CHAOS 289 16 +328 ! 7/19/92 09:31:21 (7/19/92) KLH + 0 CONFIG 197 6+1008 ! 7/19/92 11:00:02 (9/24/99) KLH + 0 CONFIG 198 6+1016 ! 9/24/99 04:07:38 (9/24/99) KLH + 0 DDT BIN 3 +671 ! 7/19/92 13:53:44 (7/19/92) KLH + 0 DSKDMP 216 9 +809 ! 7/19/92 13:56:53 (4/21/93) KLH + 0 DSKDMP BIN 2 +296 ! 7/20/92 04:35:00 (7/20/92) KLH + 0 DSKDMP BT 0 +885 ! 7/20/92 04:35:16 (7/20/92) KLH + 0 IMP 366 6 +216 ! 7/20/92 04:20:41 (9/24/99) KLH + 0 INET 139 9 +838 ! 7/20/92 04:58:30 (9/24/99) KLH + 0 ITS 1645 118 +583 ! 7/19/92 06:12:26 (9/24/99) KLH + 0 ITS 645BIN 56 +345 ! 7/20/92 04:30:13 (11/23/92) KLH + 0 ITS 645NX 56 +346 ! 9/24/99 04:09:48 (9/24/99) KLH + 0 ITS BIN 56 +346 ! 9/24/99 19:00:59 (9/24/99) KLH + 0 ITS OBIN 56 +345 ! 1/28/93 00:16:44 (1/28/93) KLH + 0 NET 33 2 +725 ! 7/19/92 06:06:21 (9/24/99) KLH + 0 TM03S DEFS5 1 +65 ! 7/20/92 04:23:56 (9/24/99) KLH + 0 TTYTYP 315 3 +69 ! 7/19/92 11:45:53 (9/24/99) KLH + +NX:.; + 0 @ AI-ITS 58 +29 ! 12/17/92 17:04:48 (4/9/93) -??- + 0 @ ITS 62 +464 ! 12/17/92 17:05:37 (1/14/93) -??- + 0 @ NSALV 12 +675 ! 12/17/92 17:05:03 (4/19/93) -??- + 0 @ SALV38 12 +540 ! 6/4/92 12:32:09 (1/14/93) -??- + 0 DDT 068BIN 3 +671 ! 7/19/92 13:53:44 (4/9/93) -??- + 0 DSKDMP 216BIN 2 +296 ! 7/20/92 04:35:00 (4/9/93) -??- + 0 DSKDMP 216BT 0 +885 ! 7/20/92 04:35:16 (4/9/93) -??- + 0 ITS 645BIN 52 +240 ! 7/20/92 04:34:15 (4/9/93) -??- + 0 NSALV 260BIN 11 +437 ! 7/20/92 04:35:29 (4/19/93) -??- +NX:.INFO.; + +NX:.MAIL.; + Empty until COMSAT launched for first time. + Most of the old files were useless, but some saved + for posterity. + 0 ID 14 0 ! 5/19/93 18:45:58 (7/23/93) KLH + 0 LIST EQV 2 +191 ! 5/24/93 15:58:39 (7/23/93) + 0 LIST QUEUE 0 +203 ! 5/24/93 15:58:39 (5/24/93) + 0 LIST MASTER 0 +203 ! 5/24/93 15:58:39 (8/20/93) + 0 LIST REMIND 0 +201 ! 5/19/93 18:45:58 (5/24/93) KLH + 0 LISTS MSGS 0 ! 5/19/93 18:45:58 (5/24/93) KLH + 0 COMSAT LAUNCH 32 +463 ! 5/19/93 18:45:44 (10/23/99) KLH + 0 NAMED ERR000 0 +8 ! 5/19/93 18:46:00 (5/19/93) KLH + 0 NAMED ERR001 0 +8 ! 5/24/93 15:58:39 (5/24/93) + 0 NAMES 2000 1 +32 ! 5/19/93 17:03:19 (5/24/93) KLH + 0 NAMES 2001 1 +59 ! 5/24/93 15:56:18 (8/20/93) KLH + 0 STATS 1 1 +738 ! 10/23/99 00:29:02 (10/23/99) -??- + 0 XLIST EQV 2 +137 ! 5/19/93 17:04:49 (5/19/93) KLH + 0 XLIST MSGS 0 +201 ! 5/19/93 17:07:49 (5/19/93) + 0 XLIST QUEUE 0 +201 ! 5/19/93 17:23:04 (5/19/93) KLH + 0 XLIST MASTER 0 +203 ! 5/19/93 17:23:04 (5/19/93) KLH + 0 XLIST REMIND 0 +201 ! 5/19/93 17:04:47 (5/19/93) KLH + 0 XNAMED ERR064 0 +9 ! 5/19/93 16:13:18 (5/19/93) KLH + 0 XNAMED ERR065 0 +9 ! 5/19/93 17:04:49 (5/19/93) KLH + L XNAMES 1062 .MAIL.;NAMES 1062 5/17/93 14:55:27 (5/17/93) KLH + 0 XNAMES 1064 0 +391 ! 5/17/93 16:53:36 (5/19/93) KLH + 0 XNAMES 1065 1 +32 ! 5/19/93 17:03:19 (5/19/93) KLH + 0 XSTATS 1 3 +166 ! 5/19/93 18:31:57 (5/19/93) KLH +NX:.TAPE0; + L LAST USE KLH;LIST 990924 9/24/99 04:32:19 (9/24/99) KLH + 0 TAPE 0 0 +46 ! 9/24/99 04:32:13 (9/24/99) KLH + 0 TAPE 1 0 +10 ! 4/19/93 18:47:27 (4/19/93) -??- + 0 TAPE 2 3 +687 ! 4/19/93 18:35:28 (4/19/93) -??- + 0 TAPE 3 0 +484 ! 4/21/93 21:07:36 (4/21/93) -??- +NX:.TECO.; +NX:.TEMP.; + +Note fucking DUMP gubbish to do FS save/restore properly: + + To save stuff, use: + DUMP FULL LINKS + + To restore stuff, use: + RELOAD LINKS CRDIR SORRY ??? + (Don't use LOAD, use RELOAD!!!) + + Fucking DUMP also appears to lose when loading up a new dir when the + first file is a link, even if the CRDIR option is set!!! + Need to create the dir by hand, then continue. + + +Idea for new DUMP format to preserve stuff better: + + Extend file header to 9 words. + Move Dump-check and don't-reap bits to LH of link,,pack# + Add sixbit author name at end. + +Must modify: + NSALV - to handle bits and potentially convert author to index. + Potentially store MFD if found, use to generate new + UFDs as needed. + DUMP - to output and read in extended format. + ITS - add new syscall to read/write bytesize and file length? + RFSIZE, SFSIZE arg1 - bytesize, arg2 - # bytes + + For SFSIZE, # bytes must be within last word or at start of + next, else error. + if (BS <= 0 || 36 < BS) error; + BPW = 36/BS; + if (((# + BPW-1) / BPW) != FILLEN) error; + + +Date: Wed, 21 Apr 93 19:10:33 -0400 +From: Alan Bawden +To: klh@us +Subject: ITS Turist Tips + + Date: Wed, 21 Apr 1993 9:34:08 BST + From: Ken Harrenstien + Sure, but why not run it? The statistics are sometimes interesting. + Also PFTHMG runs hourly, daily, monthly and yearly batch jobs, which + is a useful service in general... + + I guess. Now you have to explain what those various batch jobs are + doing there... + +Let's see... (Wow, there seem to be more of these than I remember!) +On AI, hourly we have: + + DRAGON;HOURLY CNAVRL ==> .MAIL.;COMSAT LAUNCH + +Just makes sure COMSAT doesn't stay dead for long. + + DRAGON;HOURLY GCMAIL + +This is something SRA wrote to garbage collect files from the .MAIL. +directory. I don't remember exactly what it does -- perhaps it deletes +OSTATS files that are older than a few days or something. I do remember +that there was some disagreement about how aggressive this should be. +Penny didn't want it as aggressive as SRA did. Penny won. + + DRAGON;HOURLY H3GET + +This is something I wrote that keeps the host tables on all the ITS +machines in sync. It checks the host tables on other ITS machines, and if +it finds one that is newer than the local copy, it sucks it over. + + DRAGON;HOURLY MODEMS ==> CHANNA;TS MODEMS + +This does the same thing as CHANNA;RAKASH MODEMS, this way the damn things +only stay broken for at most an hour. + + DRAGON;HOURLY TMPKIL ==> SYS2;TS TMPKIL + +I think this has something to do with cleaning up the files on .TEMP. -- I +don't know its algorithm. + + DRAGON;HOURLY UPTIME ==> BAWDEN;UPTIME BIN + +This is just a little personal hack I wrote to keep track of system uptime. +It just stores the current system uptime in the creation date of some file +on my directory. + +Then every night soon after midnight we run: + + DRAGON;DAILY BDAY + +This mails out the daily birthday greetings mail. + + DRAGON;DAILY EXPIRE ==> SYS2;TS GMSGS + +This cleans out the expired system messages on .MSGS.. + + DRAGON;DAILY NO.TS + +This searches for files named GUEST*;TS * and USER*;TS * and deletes them. +(People sharing a directory shouldn't create TS files for each other to +trip over by accident.) + +On the first of the month, and the first of the year we run: + + DRAGON;MNTHLY MNTHLY ==> DRAGON;YEARLY YEARLY + DRAGON;YEARLY YEARLY + +This just sends mail to Alan to let him know that Puff has actually run the +monthly and yearly batch jobs, even though normally these are the only +entries. + +On MC, we also have HOURLY DIGEST, which is the mailing list digestifier +(and maybe some others I don't remember). + + And what's PANDA? + +RWK;TS PANDA is the administrator's interface to PWORD. Its lets you turn +people's accounts on and off and stuff like that. Since you aren't going +to run PWORD, you don't need it. + + +Host table madness: + +Several programs will die on startup if they cannot find their own +host address or look up their name using this address. +Amongst them are FTPS. + +SYSHST;H3MAKE > - source for a small program that DRAGON is supposed to run + periodically. It invokes + SYSHST;HOSTS3 BIN (compiled from SYSHST;HOSTS3 >) + with appropriate non-trivial args that cause it to snarf up the file + SYSHST;H3TEXT > + and compile it into the binary-format file + SYSBIN;HOSTS3 > + which is used by everything else on ITS to look up host names + via this package: + SYSNET;NETWRK > + +Note that COMSAT uses a new roundabout mechanism. Instead of the NETWRK + library it now uses + SYSNET;RESOLV > + which replaces all NETWRK calls and invokes the DQ device, installed as + DEVICE;JOBDEV DQ + compiled from + SYSNET;DQXDEV > + which itself uses NETWRK to look up HOSTS3 information. This DQ + device was intended to be a temporary but more reliable replacement + for + SYSNET;DQDEV > + which is a CSTACY product attempting to do real DNS lookups via UDP. + +MIT-NX changes: + A new H3TEXT > was pulled over from + lcs.mit.edu:/hosts/.misc/hosts3.txt + This file is generated automatically by a batch job. + It was edited to remove X-terminals and chaosnet hosts, and + some NX-local names added. + +COMSAT configuration: + + Must eventually flush its HN$ symbols. + + At BUGHST/ must put the IP address of the host that deals with + (BUG RANDOM-PROGRAM) messages. + + At DOMGAT/ must put the IP address of a mail relay host. This + host will receive all mail for addresses that we can't + resolve ourselves. + + At TCPGAT/ can put IP address of a mail relay to handle *all* + external TCP/IP traffic. This is needed when there is + a firewall host like gatekeeper.us.oracle.com, sigh. + +NX .MAIL. +FREE BLOCKS #0=18478 + 0 ID 703539 0 ! 4/23/85 10:27:26 FLUSHED + 0 ID 723380 0 ! 4/23/85 10:27:26 FLUSHED + 0 LIST EQV 15 ! 4/19/90 17:41:08 FLUSHED + 0 LIST QUEUE 2 ! 4/20/90 11:07:06 FLUSHED + 0 LIST MASTER 5 ! 4/20/90 11:05:48 FLUSHED + 0 LIST REMIND 1 ! 11/19/85 18:46:42 FLUSHED + 0 LISTS MSGS 361 ! 4/20/90 11:05:47 FLUSHED + 0 LOCK UNIQUE 1 ! 4/23/85 10:27:24 + 0 *MSG EXP 2 ! 1/30/90 20:26:07 + 0 -READ- -THIS- 1 ! 12/19/86 13:47:38 + 0 .AIOLD NAMES 17 ! 7/27/85 16:35:38 + 0 .DM NAMES 3 ! 7/22/83 13:31:25 + 0 .MCNEW NAMES 19 ! 5/17/86 00:45:39 + 0 .MCOLD NAMES 24 ! 5/5/86 13:41:19 + 0 .MLOLD NAMES 9 ! 2/21/84 00:53:15 + 0 BBOARD INFO 1 ! 4/29/84 18:01:28 + 0 COMSAT BIN 31 ! 12/23/89 16:01:35 + 0 COMSAT LAUNCH Patched with: + BUGHST/ self + DOMGAT,TCPGAT/gateway + 0 COMSAT LUNCH 33 ! 9/19/90 16:17:58 AI Original + 0 COMSAT OBIN 28 ! 11/10/89 17:55:53 + 0 COMSAT OLAUNC 33 ! 11/10/89 17:56:40 FLUSHED (pure version of OBIN) + 0 FAILED STUFF 24 ! 3/29/90 22:36:45 FLUSHED + 0 MAIL 1 1 ! 9/20/90 18:15:55 FLUSHED (random ALAN stuff) + 0 MAIL 2 1 ! 9/20/90 18:15:55 FLUSHED + 0 MAILIN 1 1 ! 4/20/90 11:16:56 FLUSHED + 0 NAMED ERR094 1 ! 4/5/90 22:19:22 FLUSHED + 0 NAMED ERR096 1 ! 4/14/90 02:10:28 FLUSHED + 0 NAMED ERR097 1 ! 4/19/90 17:41:08 FLUSHED + 0 NAMES 1096 7 ! 4/14/90 02:06:27 FLUSHED + 0 NAMES 1097 7 ! 4/19/90 17:36:00 Renamed to .AIKS NAMES + 0 NAMES INFO 3 ! 7/24/89 23:41:25 + 0 OSTATS 1634 51 ! 4/18/90 16:31:55 FLUSHED + 0 OSTATS 1635 51 ! 4/19/90 23:07:52 FLUSHED + 0 XID 22 0 ! 10/30/89 19:12:43 FLUSHED + 0 XLIST EQV 1 ! 10/30/89 22:30:30 FLUSHED + 0 XLIST MSGS 0 ! 10/31/89 01:40:09 FLUSHED + 0 XLIST QUEUE 1 ! 12/23/89 16:08:06 FLUSHED + 0 XLIST MASTER 1 ! 12/23/89 16:08:06 FLUSHED + 0 XLIST REMIND 1 ! 10/30/89 19:18:24 FLUSHED + 0 XLOCK UNIQUE 1 ! 10/30/89 19:12:40 FLUSHED + 0 XNAMED ERR062 1 ! 10/30/89 19:20:18 FLUSHED + 0 XNAMED ERR063 1 ! 10/30/89 22:30:29 + L XNAMES 1062 .MAIL. NAMES 1062 + 0 XNAMES 1063 1 ! 10/30/89 22:23:34 + 0 XSTATS 1 3 ! 12/23/89 16:18:39 + +NX SYSBIN +FREE BLOCKS #0=18565 + 0 BIG 0DAT 15 ! 4/20/90 11:26:41 + L -READ- -THIS- SYSENG -READ- -THIS- + 0 AP BIN 1 ! 3/13/84 05:25:26 + 0 BOLIO 174 63 ! 12/13/82 20:16:15 + 0 BOLIO 177 67 ! 12/7/83 03:56:14 + 0 BOLIOP 191.1 1 ! 1/25/83 03:34:24 + 0 BOLIOP 191.2 1 ! 4/7/83 00:20:25 + 0 BOLIOP 191.3 1 ! 6/7/83 20:05:15 + 0 BOLIOP 191PAT 1 ! 6/7/83 20:06:01 + 0 BOLIOP 195PAT 1 ! 12/7/83 03:55:56 + 0 BRANDX 45 58 ! 12/20/82 18:05:01 + 0 BX45 (PDIR) 1 ! 12/20/82 18:04:59 + 0 BXL23 (PDIR) 1 ! 8/31/81 01:52:02 + 0 BXLSB 30 92 ! 12/20/82 18:20:08 + 0 CHTN BIN 4 ! 10/22/86 22:02:55 + 0 CNVRT BIN 2 ! 9/29/76 02:35:32 + 0 CRTSTY BIN 30 ! 8/2/89 20:58:34 + 0 CRTSTY OBIN 27 ! 7/22/85 13:18:43 + 0 CTN BIN 28 ! 12/31/84 11:07:05 + 0 CTN OBIN 28 ! 12/31/83 08:42:22 + 0 CTN SCRTST 25 ! 3/17/82 04:28:57 + 0 DDT 545BIN 27 ! 11/26/88 16:04:38 + 0 DUMP 420BIN 14 ! 6/2/88 17:59:35 + 0 DUMP 422BIN 14 ! 9/20/88 14:46:06 + 0 DUMP 442BIN 14 ! 8/4/89 15:17:23 + L DUMP BIN SYSBIN DUMP > + 0 FIDO BIN 4 ! 5/11/93 13:39:52 + 0 FILE BIN 8 ! 12/19/86 17:12:14 + 0 FILE NBIN 8 ! 2/20/89 18:08:25 + 0 FTPS BIN 11 ! 11/7/92 13:40:41 + 0 FTPS OBIN 12 ! 8/2/89 21:16:07 + 0 FTPS ORGBIN 11 ! 11/27/89 00:33:06 + 0 FTPU BIN 11 ! 8/2/89 21:12:42 + 0 FTPU OBIN 11 ! 3/5/89 15:00:03 + 0 GMSGS OBIN 3 ! 2/17/89 03:02:49 + 0 HOST1 OLD548 3 ! 3/15/83 19:00:48 + 0 HOSTS2 29 23 ! 5/2/85 19:22:53 + 0 HOSTS2 31 24 ! 6/16/85 01:54:29 + 0 HOSTS3 1560 72 ! 4/16/90 05:44:54 FLUSHED + 0 HOSTS3 1561 72 ! 4/18/90 05:16:33 FLUSHED + 0 HOSTS3 1562 72 ! 4/20/90 05:31:08 Renamed to HOSTS3 AI1562 + 0 HOSTS3 OLD 82 ! 2/24/89 04:48:23 + 0 HOSTS3 OLDOLD 71 ! 4/21/87 19:51:20 + 0 HST3BD 2 53 ! 8/23/85 01:48:56 + diff --git a/run/ksits/pubits/doc/dumpsys.help b/run/ksits/pubits/doc/dumpsys.help new file mode 100644 index 0000000..ba69c1d --- /dev/null +++ b/run/ksits/pubits/doc/dumpsys.help @@ -0,0 +1,40 @@ +Instructions for making a system-boot dump tape for ITS: + +[0] Remember to write-mount a tape-file name with the KLH10 "W" command. + +[1] After starting up DUMP in ITS, patch it so the variable WRONG is 0. + This allows writing on the tape. Sigh. + + dump^K! + DUMP .442 + *** WRONG VERSION OF DUMP--ASSEMBLED FOR AI BUT RUNNING ON NX *** + *** CERTAIN TAPE OPERATIONS WON'T BE ALLOWED *** + _ + 6146) .IOT 5,1 $^K + *wrong/'DUMPER$: -1 0 + $p + +[2] Give the command: + DUMP LIST,LINKS ; Make a WALL > listing, and include links. + At the first FILE= prompt, type "KSHACK;NXBOOT FILES ^F". + This should read in a list of files to dump. (also see note below) + +[3] Type RETURN and RETURN to start it going. + +[4] When done, do a REWIND, to ensure the tape-file is finalized. + + +NOTE: + If ^F doesn't work or the file "NXBOOT FILES" doesn't exist, enter the + following directories in response to "FILE=": + . + SYS, SYS1, SYS2, SYS3, SYSBIN + KSHACK, SYSTEM, MIDAS + SYSENG, CHANNA, DEVICE, DRAGON + MAINT (the file MAINT;PART A is a good test program) + + If creating a general "core system" dump and not just a minimal boot + set, also add these directories: + EMACS, INFO, INQUIR, KSC + SYSDOC, SYSEN1, SYSEN2, SYSHST, SYSNET + diff --git a/run/kst10/README b/run/kst10/README new file mode 100644 index 0000000..8b61cc6 --- /dev/null +++ b/run/kst10/README @@ -0,0 +1,5 @@ +The following files are derived from Digital software and subject to +Digital licensing requirements: + + ksbddt.exe (bootstrap with DDT) + ksboot.exe (disk/tape bootstrap) diff --git a/run/kst10/ksbddt.exe b/run/kst10/ksbddt.exe new file mode 100644 index 0000000..3ac48b4 Binary files /dev/null and b/run/kst10/ksbddt.exe differ diff --git a/run/kst10/ksboot.exe b/run/kst10/ksboot.exe new file mode 100644 index 0000000..8709d2a Binary files /dev/null and b/run/kst10/ksboot.exe differ diff --git a/run/kst20/README b/run/kst20/README new file mode 100644 index 0000000..de261aa --- /dev/null +++ b/run/kst20/README @@ -0,0 +1,5 @@ +The following files are derived from Digital software and subject to +Digital licensing requirements: + + smboot-k.sav (disk bootstrap) + smmtbt-k.sav (tape bootstrap) diff --git a/run/kst20/inst-kst20.ini b/run/kst20/inst-kst20.ini new file mode 100644 index 0000000..aedac39 --- /dev/null +++ b/run/kst20/inst-kst20.ini @@ -0,0 +1,19 @@ +; This is a sample KLH10 config file for a KS10 running TOPS-20. + +; Define basic KS10 device config - two RH11s each on its own Unibus + +devdef rh0 ub1 rh11 addr=776700 br=6 vec=254 +devdef rh1 ub3 rh11 addr=772440 br=6 vec=224 + +; Provide one disk, one tape in config T20 expects + +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 path=T20-RP06.0-dbd9 iodly=0 +devdef mta0 rh1.0 tm03 fmtr=tm03 type=tu45 + +; Mount installation tape, skipping past ucode and defective boot +devmount mta0 bb-d867e-bm.tap fskip=2 + +; Load fixed tape bootstrap directly +load smmtbt-k.sav + +; Now ready to GO diff --git a/run/kst20/kst20.ini b/run/kst20/kst20.ini new file mode 100644 index 0000000..35a5c3d --- /dev/null +++ b/run/kst20/kst20.ini @@ -0,0 +1,17 @@ +; This is a sample KLH10 config file for a KS10 running TOPS-20. + +; Define basic KS10 device config - two RH11s each on its own Unibus + +devdef rh0 ub1 rh11 addr=776700 br=6 vec=254 +devdef rh1 ub3 rh11 addr=772440 br=6 vec=224 + +; Provide one disk, one tape in config T20 expects + +devdef dsk0 rh0.0 rp type=rp06 format=dbd9 path=T20-RP06.0-dbd9 iodly=0 +devdef mta0 rh1.0 tm03 fmtr=tm03 type=tu45 + +; Define HOST device hackery if monitor supports it +;devdef idler 700 host + +; For convenience, load up disk bootstrap +load smboot-k.sav diff --git a/run/kst20/smboot-k.sav b/run/kst20/smboot-k.sav new file mode 100644 index 0000000..7215c42 Binary files /dev/null and b/run/kst20/smboot-k.sav differ diff --git a/run/kst20/smmtbt-k.sav b/run/kst20/smmtbt-k.sav new file mode 100644 index 0000000..864471c Binary files /dev/null and b/run/kst20/smmtbt-k.sav differ