summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Bogatov <KAction@debian.org>2018-11-29 05:18:27 +0000
committerDmitry Bogatov <KAction@debian.org>2018-11-29 05:18:27 +0000
commit78fbb41eaf3abb208abe6acfb06db005adeadf35 (patch)
treef09dac61e9f2fe6d865d76d57dac12674eec1279
Import Upstream version 0.80
-rw-r--r--BIN11
-rw-r--r--BLURB19
-rw-r--r--CHANGES7
-rw-r--r--FILES212
-rw-r--r--INSTALL26
-rw-r--r--MAN13
-rw-r--r--Makefile626
-rw-r--r--README89
-rw-r--r--SYSDEPS9
-rw-r--r--TARGETS133
-rw-r--r--TCP45
-rw-r--r--THANKS62
-rw-r--r--TODO3
-rw-r--r--UCSPI131
-rw-r--r--VERSION1
-rw-r--r--addcr.c23
-rw-r--r--addcr=x3
-rw-r--r--alloc.c32
-rw-r--r--alloc.h8
-rw-r--r--alloc=l2
-rw-r--r--alloc_re.c17
-rw-r--r--auto-str.c44
-rw-r--r--auto-str=x3
-rw-r--r--byte.h13
-rw-r--r--byte_chr.c20
-rw-r--r--byte_copy.c14
-rw-r--r--byte_cr.c16
-rw-r--r--byte_diff.c16
-rw-r--r--byte_rchr.c23
-rw-r--r--byte_zero.c13
-rw-r--r--case.h13
-rw-r--r--case=l1
-rw-r--r--case_lowers.c12
-rw-r--r--cdb.h12
-rw-r--r--cdb=l3
-rw-r--r--cdb_hash.c16
-rw-r--r--cdb_seek.c95
-rw-r--r--cdb_unpack.c12
-rw-r--r--cdbmake.h35
-rw-r--r--cdbmake=l3
-rw-r--r--cdbmake_add.c117
-rw-r--r--cdbmake_hash.c10
-rw-r--r--cdbmake_pack.c11
-rw-r--r--cdbmss.c65
-rw-r--r--cdbmss.h16
-rw-r--r--conf-bin3
-rw-r--r--conf-cc3
-rw-r--r--conf-ld3
-rw-r--r--conf-man5
-rw-r--r--date@.sh1
-rw-r--r--date@=s0
-rw-r--r--default.0.do9
-rw-r--r--default.a.do10
-rw-r--r--default.do77
-rw-r--r--default.o.do15
-rw-r--r--delcr.c37
-rw-r--r--delcr=x3
-rw-r--r--dns.c402
-rw-r--r--dns.h14
-rw-r--r--dns.lib.do14
-rw-r--r--env.c113
-rw-r--r--env.h17
-rw-r--r--env=l2
-rw-r--r--envread.c30
-rw-r--r--error.c95
-rw-r--r--error.h23
-rw-r--r--error=l2
-rw-r--r--error_str.c276
-rw-r--r--exit.h6
-rw-r--r--fd.h7
-rw-r--r--fd=l2
-rw-r--r--fd_copy.c13
-rw-r--r--fd_move.c11
-rw-r--r--find-systype.sh144
-rw-r--r--finger@.sh4
-rw-r--r--finger@=s0
-rw-r--r--fmt.h25
-rw-r--r--fmt_str.c12
-rw-r--r--fmt_ulong.c13
-rw-r--r--fs=l4
-rw-r--r--gen_alloc.h7
-rw-r--r--gen_allocdefs.h34
-rw-r--r--getln.c20
-rw-r--r--getln.h7
-rw-r--r--getln2.c31
-rw-r--r--getln=l2
-rw-r--r--getopt=l2
-rw-r--r--hassgact.h.do7
-rw-r--r--hassgprm.h.do7
-rw-r--r--haswaitp.h.do7
-rw-r--r--install.c140
-rw-r--r--install=x9
-rw-r--r--ip.c53
-rw-r--r--ip.h11
-rw-r--r--ipalloc.c7
-rw-r--r--ipalloc.h14
-rw-r--r--it.do5
-rw-r--r--make-compile.sh1
-rw-r--r--make-load.sh2
-rw-r--r--make-makelib.sh16
-rw-r--r--man.do5
-rw-r--r--mconnect.sh7
-rw-r--r--mconnect=s0
-rw-r--r--ndelay.c13
-rw-r--r--ndelay.h7
-rw-r--r--ndelay=l2
-rw-r--r--ndelay_off.c13
-rw-r--r--open.h10
-rw-r--r--open=l2
-rw-r--r--open_read.c6
-rw-r--r--open_trunc.c6
-rw-r--r--readwrite.h7
-rw-r--r--remoteinfo.c77
-rw-r--r--remoteinfo.h6
-rw-r--r--scan.h27
-rw-r--r--scan_8long.c11
-rw-r--r--scan_ulong.c11
-rw-r--r--seek.h15
-rw-r--r--seek=l4
-rw-r--r--seek_cur.c7
-rw-r--r--seek_end.c7
-rw-r--r--seek_set.c7
-rw-r--r--seek_trunc.c5
-rw-r--r--select.h.do6
-rw-r--r--select.h18
-rw-r--r--select.h29
-rw-r--r--setup.do5
-rw-r--r--sgetopt.c54
-rw-r--r--sgetopt.h21
-rw-r--r--sig.h43
-rw-r--r--sig=l7
-rw-r--r--sig_block.c40
-rw-r--r--sig_catch.c18
-rw-r--r--sig_child.c7
-rw-r--r--sig_cont.c0
-rw-r--r--sig_dfl.c82
-rw-r--r--sig_pause.c14
-rw-r--r--sig_pipe.c5
-rw-r--r--sig_term.c7
-rw-r--r--socket.lib.do8
-rw-r--r--str.h14
-rw-r--r--str=l10
-rw-r--r--str_cpy.c16
-rw-r--r--str_diff.c17
-rw-r--r--str_diffn.c18
-rw-r--r--str_len.c15
-rw-r--r--stralloc.h21
-rw-r--r--stralloc=l8
-rw-r--r--stralloc_arts.c12
-rw-r--r--stralloc_cat.c9
-rw-r--r--stralloc_catb.c15
-rw-r--r--stralloc_cats.c10
-rw-r--r--stralloc_copy.c9
-rw-r--r--stralloc_eady.c6
-rw-r--r--stralloc_opyb.c14
-rw-r--r--stralloc_opys.c10
-rw-r--r--stralloc_pend.c5
-rw-r--r--strerr.h80
-rw-r--r--strerr=l2
-rw-r--r--strerr_die.c37
-rw-r--r--strerr_sys.c12
-rw-r--r--subfd.h15
-rw-r--r--subfderr.c7
-rw-r--r--subfdin.c13
-rw-r--r--subfdout.c7
-rw-r--r--subgetopt.c79
-rw-r--r--subgetopt.h24
-rw-r--r--substdi.c91
-rw-r--r--substdio.c15
-rw-r--r--substdio.h47
-rw-r--r--substdio=l7
-rw-r--r--substdio_copy.c18
-rw-r--r--substdo.c108
-rw-r--r--tcp-environ.562
-rw-r--r--tcp-environ=01
-rw-r--r--tcpcat.sh1
-rw-r--r--tcpcat=s0
-rw-r--r--tcpclient.1134
-rw-r--r--tcpclient.c236
-rw-r--r--tcpclient=01
-rw-r--r--tcpclient=x21
-rw-r--r--tcprules.1207
-rw-r--r--tcprules.c177
-rw-r--r--tcprules=01
-rw-r--r--tcprules=x12
-rw-r--r--tcpserver.1220
-rw-r--r--tcpserver.c475
-rw-r--r--tcpserver=01
-rw-r--r--tcpserver=x25
-rw-r--r--timeoutconn.c59
-rw-r--r--timeoutconn.h6
-rw-r--r--timeoutread.c22
-rw-r--r--timeoutread.h6
-rw-r--r--timeoutwrite.c22
-rw-r--r--timeoutwrite.h6
-rw-r--r--trycpp.c7
-rw-r--r--trylsock.c4
-rw-r--r--tryrsolv.c4
-rw-r--r--trysgact.c10
-rw-r--r--trysgprm.c10
-rw-r--r--trysysel.c8
-rw-r--r--tryulong32.c11
-rw-r--r--trywaitp.c7
-rw-r--r--uint32.h.do7
-rw-r--r--uint32.h16
-rw-r--r--uint32.h26
-rw-r--r--wait.h14
-rw-r--r--wait=l1
-rw-r--r--wait_nohang.c12
-rw-r--r--warn-auto.sh2
-rw-r--r--who@.sh1
-rw-r--r--who@=s0
212 files changed, 6997 insertions, 0 deletions
diff --git a/BIN b/BIN
new file mode 100644
index 0000000..a7b03c7
--- /dev/null
+++ b/BIN
@@ -0,0 +1,11 @@
+d:::755:::
+c:::711:/:tcpclient:
+c:::711:/:tcpserver:
+c:::711:/:tcprules:
+c:::711:/:addcr:
+c:::711:/:delcr:
+c:::755:/:who@:
+c:::755:/:date@:
+c:::755:/:finger@:
+c:::755:/:tcpcat:
+c:::755:/:mconnect:
diff --git a/BLURB b/BLURB
new file mode 100644
index 0000000..754dc0f
--- /dev/null
+++ b/BLURB
@@ -0,0 +1,19 @@
+tcpclient and tcpserver are easy-to-use command-line tools for building
+TCP client-server applications. tcpclient makes a TCP connection and
+runs a program of your choice. tcpserver waits for incoming connections
+and, for each connection, runs a program of your choice. Your program
+receives environment variables showing the local and remote host names,
+IP addresses, and port numbers.
+
+tcpserver offers a concurrency limit to protect you from running out of
+processes and memory. When you are handling 40 (by default) simultaneous
+connections, tcpserver smoothly defers acceptance of new connections.
+
+tcpserver also provides TCP access control features, similar to
+tcp-wrappers/tcpd's hosts.allow but much faster. Its access control
+rules are compiled into a hashed format with cdb, so it can easily deal
+with thousands of different hosts.
+
+tcpclient and tcpserver conform to UCSPI, the UNIX Client-Server Program
+Interface, using the TCP protocol. UCSPI tools are available for several
+different networks.
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..23118aa
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,7 @@
+19980118 ucspi-tcp 0.80, beta.
+19970410 ucspi-tcp 0.73, beta.
+19960922 ucspi-tcp 0.72, beta.
+19960914 ucspi-tcp 0.71, beta.
+19960903 ucspi-tcp 0.70, beta.
+19960803 ucspi-tcp 0.60, alpha.
+19960311 ucspi-tcp 0.50, alpha.
diff --git a/FILES b/FILES
new file mode 100644
index 0000000..22d469e
--- /dev/null
+++ b/FILES
@@ -0,0 +1,212 @@
+BLURB
+README
+INSTALL
+TODO
+THANKS
+CHANGES
+UCSPI
+TCP
+FILES
+BIN
+MAN
+VERSION
+SYSDEPS
+TARGETS
+Makefile
+tcpclient=0
+tcpclient.1
+tcpclient=x
+tcpclient.c
+tcpserver=0
+tcpserver.1
+tcpserver=x
+tcpserver.c
+tcprules=0
+tcprules.1
+tcprules=x
+tcprules.c
+tcp-environ=0
+tcp-environ.5
+addcr=x
+addcr.c
+delcr=x
+delcr.c
+date@=s
+date@.sh
+finger@=s
+finger@.sh
+who@=s
+who@.sh
+mconnect=s
+mconnect.sh
+tcpcat=s
+tcpcat.sh
+it.do
+man.do
+setup.do
+default.do
+default.a.do
+default.o.do
+default.0.do
+conf-cc
+conf-ld
+find-systype.sh
+make-compile.sh
+make-load.sh
+make-makelib.sh
+trycpp.c
+warn-auto.sh
+conf-bin
+conf-man
+auto-str=x
+install=x
+auto-str.c
+install.c
+substdio=l
+substdio.h
+substdio.c
+substdi.c
+substdo.c
+substdio_copy.c
+subfd.h
+subfderr.c
+subfdout.c
+subfdin.c
+readwrite.h
+exit.h
+error=l
+error.h
+error.c
+error_str.c
+str=l
+byte.h
+byte_chr.c
+byte_rchr.c
+byte_copy.c
+byte_cr.c
+byte_diff.c
+byte_zero.c
+str.h
+str_cpy.c
+str_diff.c
+str_diffn.c
+str_len.c
+sig=l
+sig.h
+sig_block.c
+sig_catch.c
+sig_dfl.c
+sig_pipe.c
+sig_cont.c
+sig_child.c
+sig_pause.c
+sig_term.c
+hassgact.h.do
+hassgprm.h.do
+trysgact.c
+trysgprm.c
+fd=l
+fd.h
+fd_copy.c
+fd_move.c
+ip.h
+ip.c
+ipalloc.h
+ipalloc.c
+case=l
+case.h
+case_lowers.c
+getopt=l
+sgetopt.h
+sgetopt.c
+subgetopt.h
+subgetopt.c
+fs=l
+fmt.h
+fmt_str.c
+fmt_ulong.c
+scan.h
+scan_ulong.c
+scan_8long.c
+env=l
+env.h
+env.c
+envread.c
+dns.h
+dns.c
+dns.lib.do
+socket.lib.do
+tryrsolv.c
+trylsock.c
+timeoutread.h
+timeoutread.c
+timeoutwrite.h
+timeoutwrite.c
+timeoutconn.h
+timeoutconn.c
+remoteinfo.h
+remoteinfo.c
+wait=l
+wait.h
+wait_nohang.c
+trywaitp.c
+haswaitp.h.do
+select.h.do
+select.h1
+select.h2
+trysysel.c
+stralloc=l
+gen_alloc.h
+gen_allocdefs.h
+stralloc.h
+stralloc_eady.c
+stralloc_pend.c
+stralloc_copy.c
+stralloc_opyb.c
+stralloc_opys.c
+stralloc_cat.c
+stralloc_catb.c
+stralloc_cats.c
+stralloc_arts.c
+alloc=l
+alloc.h
+alloc.c
+alloc_re.c
+ndelay=l
+ndelay.h
+ndelay.c
+ndelay_off.c
+strerr=l
+strerr.h
+strerr_sys.c
+strerr_die.c
+open=l
+open.h
+open_read.c
+open_trunc.c
+getln=l
+getln.h
+getln.c
+getln2.c
+cdb=l
+cdbmake=l
+cdb.h
+cdb_hash.c
+cdb_seek.c
+cdb_unpack.c
+cdbmake.h
+cdbmake_add.c
+cdbmake_hash.c
+cdbmake_pack.c
+cdbmss.h
+cdbmss.c
+uint32.h.do
+uint32.h1
+uint32.h2
+tryulong32.c
+seek=l
+seek.h
+seek_cur.c
+seek_end.c
+seek_set.c
+seek_trunc.c
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..9244c4d
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,26 @@
+Like any other piece of software (and information generally), ucspi-tcp
+comes with NO WARRANTY.
+
+
+Things you have to decide before starting:
+
+* Where programs will be installed, normally /usr/local/bin. To change
+this directory, edit conf-bin now.
+
+* Where man pages will be installed, normally /usr/local/man. To change
+this directory, edit conf-man now.
+
+
+How to install:
+
+ 1. Compile the programs:
+ % make
+ 2. Create the formatted man pages, *.0:
+ % make man
+ 3. Install the programs and man pages:
+ # make setup
+
+
+That's it! To report success:
+ % ( echo 'First M. Last'; cat `cat SYSDEPS` ) | mail djb-qst@cr.yp.to
+Replace First M. Last with your name.
diff --git a/MAN b/MAN
new file mode 100644
index 0000000..7f35a81
--- /dev/null
+++ b/MAN
@@ -0,0 +1,13 @@
+d:::755:::
+d:::755:/man1::
+d:::755:/cat1::
+d:::755:/man5::
+d:::755:/cat5::
+c:::644:/man1/:tcpclient.1:
+c:::644:/cat1/:tcpclient.0:
+c:::644:/man1/:tcpserver.1:
+c:::644:/cat1/:tcpserver.0:
+c:::644:/man1/:tcprules.1:
+c:::644:/cat1/:tcprules.0:
+c:::644:/man5/:tcp-environ.5:
+c:::644:/cat5/:tcp-environ.0:
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..be4a723
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,626 @@
+# Don't edit Makefile! Use conf-* for configuration.
+
+SHELL=/bin/sh
+
+default: it
+
+addcr: \
+load addcr.o substdio.a error.a str.a
+ ./load addcr substdio.a error.a str.a
+
+addcr.o: \
+compile addcr.c substdio.h subfd.h exit.h
+ ./compile addcr.c
+
+alloc.a: \
+makelib alloc.o alloc_re.o
+ ./makelib alloc.a alloc.o alloc_re.o
+
+alloc.o: \
+compile alloc.c alloc.h error.h
+ ./compile alloc.c
+
+alloc_re.o: \
+compile alloc_re.c alloc.h byte.h
+ ./compile alloc_re.c
+
+auto-ccld.sh: \
+conf-cc conf-ld warn-auto.sh
+ ( cat warn-auto.sh; \
+ echo CC=\'`head -1 conf-cc`\'; \
+ echo LD=\'`head -1 conf-ld`\' \
+ ) > auto-ccld.sh
+
+byte_chr.o: \
+compile byte_chr.c byte.h
+ ./compile byte_chr.c
+
+byte_copy.o: \
+compile byte_copy.c byte.h
+ ./compile byte_copy.c
+
+byte_cr.o: \
+compile byte_cr.c byte.h
+ ./compile byte_cr.c
+
+byte_diff.o: \
+compile byte_diff.c byte.h
+ ./compile byte_diff.c
+
+byte_rchr.o: \
+compile byte_rchr.c byte.h
+ ./compile byte_rchr.c
+
+byte_zero.o: \
+compile byte_zero.c byte.h
+ ./compile byte_zero.c
+
+case.a: \
+makelib case_lowers.o
+ ./makelib case.a case_lowers.o
+
+case_lowers.o: \
+compile case_lowers.c case.h
+ ./compile case_lowers.c
+
+cdb.a: \
+makelib cdb_hash.o cdb_unpack.o cdb_seek.o
+ ./makelib cdb.a cdb_hash.o cdb_unpack.o cdb_seek.o
+
+cdb_hash.o: \
+compile cdb_hash.c cdb.h uint32.h
+ ./compile cdb_hash.c
+
+cdb_seek.o: \
+compile cdb_seek.c cdb.h uint32.h
+ ./compile cdb_seek.c
+
+cdb_unpack.o: \
+compile cdb_unpack.c cdb.h uint32.h
+ ./compile cdb_unpack.c
+
+cdbmake.a: \
+makelib cdbmake_pack.o cdbmake_hash.o cdbmake_add.o
+ ./makelib cdbmake.a cdbmake_pack.o cdbmake_hash.o \
+ cdbmake_add.o
+
+cdbmake_add.o: \
+compile cdbmake_add.c cdbmake.h uint32.h
+ ./compile cdbmake_add.c
+
+cdbmake_hash.o: \
+compile cdbmake_hash.c cdbmake.h uint32.h
+ ./compile cdbmake_hash.c
+
+cdbmake_pack.o: \
+compile cdbmake_pack.c cdbmake.h uint32.h
+ ./compile cdbmake_pack.c
+
+cdbmss.o: \
+compile cdbmss.c readwrite.h seek.h alloc.h cdbmss.h cdbmake.h \
+uint32.h substdio.h
+ ./compile cdbmss.c
+
+compile: \
+make-compile warn-auto.sh systype
+ ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \
+ compile
+ chmod 755 compile
+
+date@: \
+warn-auto.sh date@.sh conf-bin
+ cat warn-auto.sh date@.sh \
+ | sed s}BIN}"`head -1 conf-bin`"}g > date@
+ chmod 755 date@
+
+delcr: \
+load delcr.o substdio.a error.a str.a
+ ./load delcr substdio.a error.a str.a
+
+delcr.o: \
+compile delcr.c substdio.h subfd.h exit.h
+ ./compile delcr.c
+
+dns.lib: \
+tryrsolv.c compile load socket.lib dns.o ipalloc.o ip.o stralloc.a \
+alloc.a error.a fs.a str.a
+ ( ( ./compile tryrsolv.c && ./load tryrsolv dns.o \
+ ipalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \
+ -lresolv `cat socket.lib` ) >/dev/null 2>&1 \
+ && echo -lresolv || exit 0 ) > dns.lib
+ rm -f tryrsolv.o tryrsolv
+
+dns.o: \
+compile dns.c ip.h ipalloc.h gen_alloc.h fmt.h alloc.h str.h \
+stralloc.h dns.h case.h
+ ./compile dns.c
+
+env.a: \
+makelib env.o envread.o
+ ./makelib env.a env.o envread.o
+
+env.o: \
+compile env.c str.h alloc.h env.h
+ ./compile env.c
+
+envread.o: \
+compile envread.c env.h str.h
+ ./compile envread.c
+
+error.a: \
+makelib error.o error_str.o
+ ./makelib error.a error.o error_str.o
+
+error.o: \
+compile error.c error.h
+ ./compile error.c
+
+error_str.o: \
+compile error_str.c error.h
+ ./compile error_str.c
+
+fd.a: \
+makelib fd_copy.o fd_move.o
+ ./makelib fd.a fd_copy.o fd_move.o
+
+fd_copy.o: \
+compile fd_copy.c fd.h
+ ./compile fd_copy.c
+
+fd_move.o: \
+compile fd_move.c fd.h
+ ./compile fd_move.c
+
+find-systype: \
+find-systype.sh auto-ccld.sh
+ cat auto-ccld.sh find-systype.sh > find-systype
+ chmod 755 find-systype
+
+finger@: \
+warn-auto.sh finger@.sh conf-bin
+ cat warn-auto.sh finger@.sh \
+ | sed s}BIN}"`head -1 conf-bin`"}g > finger@
+ chmod 755 finger@
+
+fmt_str.o: \
+compile fmt_str.c fmt.h
+ ./compile fmt_str.c
+
+fmt_ulong.o: \
+compile fmt_ulong.c fmt.h
+ ./compile fmt_ulong.c
+
+fs.a: \
+makelib fmt_str.o fmt_ulong.o scan_ulong.o scan_8long.o
+ ./makelib fs.a fmt_str.o fmt_ulong.o scan_ulong.o \
+ scan_8long.o
+
+getln.a: \
+makelib getln.o getln2.o
+ ./makelib getln.a getln.o getln2.o
+
+getln.o: \
+compile getln.c substdio.h byte.h stralloc.h gen_alloc.h getln.h
+ ./compile getln.c
+
+getln2.o: \
+compile getln2.c substdio.h stralloc.h gen_alloc.h byte.h getln.h
+ ./compile getln2.c
+
+getopt.a: \
+makelib subgetopt.o sgetopt.o
+ ./makelib getopt.a subgetopt.o sgetopt.o
+
+hassgact.h: \
+trysgact.c compile load
+ ( ( ./compile trysgact.c && ./load trysgact ) >/dev/null \
+ 2>&1 \
+ && echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h
+ rm -f trysgact.o trysgact
+
+hassgprm.h: \
+trysgprm.c compile load
+ ( ( ./compile trysgprm.c && ./load trysgprm ) >/dev/null \
+ 2>&1 \
+ && echo \#define HASSIGPROCMASK 1 || exit 0 ) > hassgprm.h
+ rm -f trysgprm.o trysgprm
+
+haswaitp.h: \
+trywaitp.c compile load
+ ( ( ./compile trywaitp.c && ./load trywaitp ) >/dev/null \
+ 2>&1 \
+ && echo \#define HASWAITPID 1 || exit 0 ) > haswaitp.h
+ rm -f trywaitp.o trywaitp
+
+install: \
+load install.o getln.a strerr.a substdio.a stralloc.a alloc.a open.a \
+error.a str.a fs.a
+ ./load install getln.a strerr.a substdio.a stralloc.a \
+ alloc.a open.a error.a str.a fs.a
+
+install.o: \
+compile install.c substdio.h stralloc.h gen_alloc.h getln.h \
+readwrite.h exit.h open.h error.h strerr.h byte.h
+ ./compile install.c
+
+ip.o: \
+compile ip.c fmt.h scan.h ip.h
+ ./compile ip.c
+
+ipalloc.o: \
+compile ipalloc.c alloc.h gen_allocdefs.h ip.h ipalloc.h gen_alloc.h
+ ./compile ipalloc.c
+
+it: \
+tcpclient tcpserver tcprules who@ date@ finger@ tcpcat mconnect addcr \
+delcr
+
+load: \
+make-load warn-auto.sh systype
+ ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load
+ chmod 755 load
+
+make-compile: \
+make-compile.sh auto-ccld.sh
+ cat auto-ccld.sh make-compile.sh > make-compile
+ chmod 755 make-compile
+
+make-load: \
+make-load.sh auto-ccld.sh
+ cat auto-ccld.sh make-load.sh > make-load
+ chmod 755 make-load
+
+make-makelib: \
+make-makelib.sh auto-ccld.sh
+ cat auto-ccld.sh make-makelib.sh > make-makelib
+ chmod 755 make-makelib
+
+makelib: \
+make-makelib warn-auto.sh systype
+ ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \
+ makelib
+ chmod 755 makelib
+
+man: \
+tcpclient.0 tcpserver.0 tcprules.0 tcp-environ.0
+
+mconnect: \
+warn-auto.sh mconnect.sh conf-bin
+ cat warn-auto.sh mconnect.sh \
+ | sed s}BIN}"`head -1 conf-bin`"}g > mconnect
+ chmod 755 mconnect
+
+ndelay.a: \
+makelib ndelay.o ndelay_off.o
+ ./makelib ndelay.a ndelay.o ndelay_off.o
+
+ndelay.o: \
+compile ndelay.c ndelay.h
+ ./compile ndelay.c
+
+ndelay_off.o: \
+compile ndelay_off.c ndelay.h
+ ./compile ndelay_off.c
+
+open.a: \
+makelib open_read.o open_trunc.o
+ ./makelib open.a open_read.o open_trunc.o
+
+open_read.o: \
+compile open_read.c open.h
+ ./compile open_read.c
+
+open_trunc.o: \
+compile open_trunc.c open.h
+ ./compile open_trunc.c
+
+remoteinfo.o: \
+compile remoteinfo.c byte.h substdio.h ip.h fmt.h timeoutconn.h \
+timeoutread.h timeoutwrite.h remoteinfo.h
+ ./compile remoteinfo.c
+
+scan_8long.o: \
+compile scan_8long.c scan.h
+ ./compile scan_8long.c
+
+scan_ulong.o: \
+compile scan_ulong.c scan.h
+ ./compile scan_ulong.c
+
+seek.a: \
+makelib seek_cur.o seek_end.o seek_set.o seek_trunc.o
+ ./makelib seek.a seek_cur.o seek_end.o seek_set.o \
+ seek_trunc.o
+
+seek_cur.o: \
+compile seek_cur.c seek.h
+ ./compile seek_cur.c
+
+seek_end.o: \
+compile seek_end.c seek.h
+ ./compile seek_end.c
+
+seek_set.o: \
+compile seek_set.c seek.h
+ ./compile seek_set.c
+
+seek_trunc.o: \
+compile seek_trunc.c seek.h
+ ./compile seek_trunc.c
+
+select.h: \
+compile trysysel.c select.h1 select.h2
+ ( ./compile trysysel.c >/dev/null 2>&1 \
+ && cat select.h2 || cat select.h1 ) > select.h
+ rm -f trysysel.o trysysel
+
+setup: \
+it man install conf-bin conf-man BIN MAN
+ ./install "`head -1 conf-bin`" < BIN
+ ./install "`head -1 conf-man`" < MAN
+
+sgetopt.o: \
+compile sgetopt.c substdio.h subfd.h sgetopt.h subgetopt.h
+ ./compile sgetopt.c
+
+sig.a: \
+makelib sig_block.o sig_catch.o sig_pause.o sig_dfl.o sig_pipe.o \
+sig_child.o sig_term.o
+ ./makelib sig.a sig_block.o sig_catch.o sig_pause.o \
+ sig_dfl.o sig_pipe.o sig_child.o sig_term.o
+
+sig_block.o: \
+compile sig_block.c sig.h hassgprm.h
+ ./compile sig_block.c
+
+sig_catch.o: \
+compile sig_catch.c sig.h hassgact.h
+ ./compile sig_catch.c
+
+sig_child.o: \
+compile sig_child.c sig.h
+ ./compile sig_child.c
+
+sig_dfl.o: \
+compile sig_dfl.c sig.h hassgact.h hassgprm.h
+ ./compile sig_dfl.c
+
+sig_pause.o: \
+compile sig_pause.c sig.h hassgprm.h
+ ./compile sig_pause.c
+
+sig_pipe.o: \
+compile sig_pipe.c sig.h
+ ./compile sig_pipe.c
+
+sig_term.o: \
+compile sig_term.c sig.h
+ ./compile sig_term.c
+
+socket.lib: \
+trylsock.c compile load
+ ( ( ./compile trylsock.c && \
+ ./load trylsock -lsocket -lnsl ) >/dev/null 2>&1 \
+ && echo -lsocket -lnsl || exit 0 ) > socket.lib
+ rm -f trylsock.o trylsock
+
+str.a: \
+makelib str_len.o str_diff.o str_diffn.o str_cpy.o byte_chr.o \
+byte_rchr.o byte_diff.o byte_copy.o byte_cr.o byte_zero.o
+ ./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \
+ byte_chr.o byte_rchr.o byte_diff.o byte_copy.o byte_cr.o \
+ byte_zero.o
+
+str_cpy.o: \
+compile str_cpy.c str.h
+ ./compile str_cpy.c
+
+str_diff.o: \
+compile str_diff.c str.h
+ ./compile str_diff.c
+
+str_diffn.o: \
+compile str_diffn.c str.h
+ ./compile str_diffn.c
+
+str_len.o: \
+compile str_len.c str.h
+ ./compile str_len.c
+
+stralloc.a: \
+makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \
+stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \
+stralloc_catb.o
+ ./makelib stralloc.a stralloc_eady.o stralloc_pend.o \
+ stralloc_copy.o stralloc_opys.o stralloc_opyb.o \
+ stralloc_cat.o stralloc_cats.o stralloc_catb.o
+
+stralloc_cat.o: \
+compile stralloc_cat.c byte.h stralloc.h gen_alloc.h
+ ./compile stralloc_cat.c
+
+stralloc_catb.o: \
+compile stralloc_catb.c stralloc.h gen_alloc.h byte.h
+ ./compile stralloc_catb.c
+
+stralloc_cats.o: \
+compile stralloc_cats.c byte.h str.h stralloc.h gen_alloc.h
+ ./compile stralloc_cats.c
+
+stralloc_copy.o: \
+compile stralloc_copy.c byte.h stralloc.h gen_alloc.h
+ ./compile stralloc_copy.c
+
+stralloc_eady.o: \
+compile stralloc_eady.c alloc.h stralloc.h gen_alloc.h \
+gen_allocdefs.h
+ ./compile stralloc_eady.c
+
+stralloc_opyb.o: \
+compile stralloc_opyb.c stralloc.h gen_alloc.h byte.h
+ ./compile stralloc_opyb.c
+
+stralloc_opys.o: \
+compile stralloc_opys.c byte.h str.h stralloc.h gen_alloc.h
+ ./compile stralloc_opys.c
+
+stralloc_pend.o: \
+compile stralloc_pend.c alloc.h stralloc.h gen_alloc.h \
+gen_allocdefs.h
+ ./compile stralloc_pend.c
+
+strerr.a: \
+makelib strerr_sys.o strerr_die.o
+ ./makelib strerr.a strerr_sys.o strerr_die.o
+
+strerr_die.o: \
+compile strerr_die.c substdio.h subfd.h exit.h strerr.h
+ ./compile strerr_die.c
+
+strerr_sys.o: \
+compile strerr_sys.c error.h strerr.h
+ ./compile strerr_sys.c
+
+subfderr.o: \
+compile subfderr.c readwrite.h substdio.h subfd.h
+ ./compile subfderr.c
+
+subfdin.o: \
+compile subfdin.c readwrite.h substdio.h subfd.h
+ ./compile subfdin.c
+
+subfdout.o: \
+compile subfdout.c readwrite.h substdio.h subfd.h
+ ./compile subfdout.c
+
+subgetopt.o: \
+compile subgetopt.c subgetopt.h
+ ./compile subgetopt.c
+
+substdi.o: \
+compile substdi.c substdio.h byte.h error.h
+ ./compile substdi.c
+
+substdio.a: \
+makelib substdio.o substdi.o substdo.o subfderr.o subfdout.o \
+subfdin.o substdio_copy.o
+ ./makelib substdio.a substdio.o substdi.o substdo.o \
+ subfderr.o subfdout.o subfdin.o substdio_copy.o
+
+substdio.o: \
+compile substdio.c substdio.h
+ ./compile substdio.c
+
+substdio_copy.o: \
+compile substdio_copy.c substdio.h
+ ./compile substdio_copy.c
+
+substdo.o: \
+compile substdo.c substdio.h str.h byte.h error.h
+ ./compile substdo.c
+
+systype: \
+find-systype trycpp.c
+ ./find-systype > systype
+
+tcp-environ.0: \
+tcp-environ.5
+ nroff -man tcp-environ.5 > tcp-environ.0
+
+tcpcat: \
+warn-auto.sh tcpcat.sh conf-bin
+ cat warn-auto.sh tcpcat.sh \
+ | sed s}BIN}"`head -1 conf-bin`"}g > tcpcat
+ chmod 755 tcpcat
+
+tcpclient: \
+load tcpclient.o ip.o ipalloc.o dns.o remoteinfo.o timeoutconn.o \
+timeoutread.o timeoutwrite.o stralloc.a env.a alloc.a ndelay.a \
+substdio.a error.a str.a sig.a fd.a case.a getopt.a fs.a dns.lib \
+socket.lib
+ ./load tcpclient ip.o ipalloc.o dns.o remoteinfo.o \
+ timeoutconn.o timeoutread.o timeoutwrite.o stralloc.a env.a \
+ alloc.a ndelay.a substdio.a error.a str.a sig.a fd.a case.a \
+ getopt.a fs.a `cat dns.lib` `cat socket.lib`
+
+tcpclient.0: \
+tcpclient.1
+ nroff -man tcpclient.1 > tcpclient.0
+
+tcpclient.o: \
+compile tcpclient.c substdio.h stralloc.h gen_alloc.h str.h byte.h \
+error.h sig.h subfd.h fd.h ip.h ipalloc.h case.h sgetopt.h \
+subgetopt.h exit.h scan.h fmt.h env.h dns.h remoteinfo.h
+ ./compile tcpclient.c
+
+tcprules: \
+load tcprules.o cdbmss.o cdbmake.a getln.a strerr.a stralloc.a \
+substdio.a alloc.a error.a open.a seek.a str.a fs.a
+ ./load tcprules cdbmss.o cdbmake.a getln.a strerr.a \
+ stralloc.a substdio.a alloc.a error.a open.a seek.a str.a \
+ fs.a
+
+tcprules.0: \
+tcprules.1
+ nroff -man tcprules.1 > tcprules.0
+
+tcprules.o: \
+compile tcprules.c strerr.h stralloc.h gen_alloc.h getln.h substdio.h \
+subfd.h exit.h fmt.h byte.h cdbmss.h cdbmake.h uint32.h
+ ./compile tcprules.c
+
+tcpserver: \
+load tcpserver.o ip.o ipalloc.o dns.o remoteinfo.o timeoutconn.o \
+timeoutread.o timeoutwrite.o cdb.a open.a wait.a strerr.a stralloc.a \
+env.a ndelay.a alloc.a getopt.a substdio.a error.a str.a sig.a fd.a \
+case.a fs.a dns.lib socket.lib
+ ./load tcpserver ip.o ipalloc.o dns.o remoteinfo.o \
+ timeoutconn.o timeoutread.o timeoutwrite.o cdb.a open.a \
+ wait.a strerr.a stralloc.a env.a ndelay.a alloc.a getopt.a \
+ substdio.a error.a str.a sig.a fd.a case.a fs.a `cat \
+ dns.lib` `cat socket.lib`
+
+tcpserver.0: \
+tcpserver.1
+ nroff -man tcpserver.1 > tcpserver.0
+
+tcpserver.o: \
+compile tcpserver.c strerr.h substdio.h stralloc.h gen_alloc.h \
+alloc.h readwrite.h fd.h sig.h wait.h ip.h ipalloc.h dns.h str.h \
+case.h byte.h sgetopt.h subgetopt.h remoteinfo.h exit.h open.h scan.h \
+fmt.h env.h cdb.h uint32.h
+ ./compile tcpserver.c
+
+timeoutconn.o: \
+compile timeoutconn.c ndelay.h select.h error.h readwrite.h ip.h \
+byte.h timeoutconn.h
+ ./compile timeoutconn.c
+
+timeoutread.o: \
+compile timeoutread.c timeoutread.h select.h error.h readwrite.h
+ ./compile timeoutread.c
+
+timeoutwrite.o: \
+compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h
+ ./compile timeoutwrite.c
+
+uint32.h: \
+tryulong32.c compile load uint32.h1 uint32.h2
+ ( ( ./compile tryulong32.c && ./load tryulong32 && \
+ ./tryulong32 ) >/dev/null 2>&1 \
+ && cat uint32.h2 || cat uint32.h1 ) > uint32.h
+ rm -f tryulong32.o tryulong32
+
+wait.a: \
+makelib wait_nohang.o
+ ./makelib wait.a wait_nohang.o
+
+wait_nohang.o: \
+compile wait_nohang.c haswaitp.h
+ ./compile wait_nohang.c
+
+who@: \
+warn-auto.sh who@.sh conf-bin
+ cat warn-auto.sh who@.sh \
+ | sed s}BIN}"`head -1 conf-bin`"}g > who@
+ chmod 755 who@
diff --git a/README b/README
new file mode 100644
index 0000000..772f780
--- /dev/null
+++ b/README
@@ -0,0 +1,89 @@
+ucspi-tcp 0.80, beta.
+19980118
+Copyright 1998
+D. J. Bernstein, djb@pobox.com
+
+tcpclient and tcpserver are easy-to-use command-line tools for building
+TCP client-server applications. See BLURB for a more detailed
+advertisement.
+
+You may distribute unmodified copies of the ucspi-tcp package.
+
+INSTALL says how to set up tcpclient and tcpserver.
+
+See http://pobox.com/~djb/ucspi-tcp.html for the latest information
+about ucspi-tcp. See http://pobox.com/~djb/proto/ucspi.txt for general
+information about UCSPI.
+
+The rest of this file is a list of systypes where various versions of
+ucspi-tcp have been reported to work. 0.70 was the first beta version.
+
+0.73: aix-4-2-:-:-:000055247900-:- (tnx JLB)
+0.73: bsd.os-2.0.1-:i386-:-:pentium-:-
+0.73: bsd.os-2.1-:i386-:-:pentium-:- (tnx MPS)
+0.73: bsd.os-3.0-:i386-:-:pentium-:- (tnx SN)
+0.73: freebsd-2.1.0-release-:i386-:-:i486.dx2-:- (tnx NM)
+0.73: freebsd-2.1.0-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx MBS)
+0.73: freebsd-2.2-970422-releng-:i386-:-:pentium-:- (tnx TM)
+0.73: freebsd-2.2-970618-releng-:i386-:-:pentium-:- (tnx LST)
+0.72: freebsd-2.2-release-:i386-:-:pentium-:- (tnx frank@news=???)
+0.73: freebsd-2.2-stable-:i386-:-:pentium-:- (tnx JJE)
+0.73: freebsd-2.2.1-release-:i386-:-:-:- (tnx TM)
+0.73: freebsd-2.2.1-release-:i386-:-:pentium-:- (tnx RWL)
+0.73: freebsd-2.2.2-release-:i386-:-:amd.unknown-:- (tnx FN)
+0.73: freebsd-2.2.2-release-:i386-:-:pentium-:- (tnx BJR)
+0.73: freebsd-2.2.5-release-:i386-:-:pentium.pro-:- (tnx AI)
+0.73: freebsd-3.0-971012-snap-:i386-:-:i486.dx2-:- (tnx AY)
+0.72: freebsd-3.0-current-:i386-:-:pentium-:- (tnx black@shadow=???)
+0.72: hp-ux-b.09.00-a-:-:-:9000.360-:- (tnx VV)
+0.72: hp-ux-b.10.01-a-:-:-:9000.715-:- (tnx BG)
+0.72: irix-5.3-11091812-:-:-:ip22-:- (tnx PW)
+0.73: irix-6.2-03131015-:-:-:ip22-:- (tnx JL)
+0.72: linux-1.2.13-:i386-:-:i486-:- (tnx JDM)
+0.73: linux-2.0.18-:i386-:-:pentium-:- (tnx JDM)
+0.72: linux-2.0.21-:i386-:-:pentium-:- (tnx SJ)
+0.72: linux-2.0.23-:i386-:-:i486-:- (tnx J2W)
+0.72: linux-2.0.24-:i386-:-:pentium-:- (tnx VV)
+0.72: linux-2.0.25-:i386-:-:i486-:- (tnx FPL)
+0.73: linux-2.0.25-:i386-:-:pentium-:- (tnx AW)
+0.72: linux-2.0.26-:i386-:-:pentium-:- (tnx root@pointer=???)
+0.73: linux-2.0.27-:i386-:-:ppro-:- (tnx PMK)
+0.73: linux-2.0.28-:alpha-:-:alpha-:- (tnx T2K)
+0.73: linux-2.0.29-:i386-:-:i486-:- (tnx keith@gadget=???)
+0.73: linux-2.0.29-:i386-:-:pentium-:- (tnx RAL)
+0.73: linux-2.0.29-:i386-:-:ppro-:- (tnx GDP)
+0.73: linux-2.0.30-:-:-:sparc-:- (tnx DJ)
+0.73: linux-2.0.30-:i386-:-:i386-:- (tnx DMV)
+0.73: linux-2.0.30-:i386-:-:pentium-:- (tnx AV)
+0.73: linux-2.0.32-:i386-:-:pentium-:- (tnx AS)
+0.73: linux-2.0.7-:i386-:-:i486-:- (tnx TLM)
+0.73: linux-2.1.30-:i386-:-:pentium-:- (tnx RAS)
+0.73: linux-2.1.36-:i386-:-:pentium-:- (tnx JF)
+0.73: netbsd-1.1-:i386-:-:pentium.(genuineintel.586-class.cpu)-:- (tnx GL)
+0.73: netbsd-1.3_alpha-:i386-:-:intel.pentium.(p54c).(586-class)-:- (tnx GL)
+0.73: nextstep-3.3-:mc680x0-:-:68040-:- (tnx WEB)
+0.73: osf1-v3.2-214-:-:-:alpha-:- (tnx A2P)
+0.73: osf1-v4.0-564-:-:-:alpha-:- (tnx A2P)
+0.73: sunos-4.1.3_u1-1-:sparc-:sun4-:sun4c-:sun4c- (tnx MBS)
+0.73: sunos-4.1.3_u1-4-:unknown-:sun4-:sun4m-:sun4m- (tnx J2B)
+0.73: sunos-4.1.4-2-:sparc-:sun4-:sun4m-:sun4m-
+0.73: sunos-5.4-generic-:sparc-:sun4-:sun4m-:sun4m-
+0.72: sunos-5.4-generic_101945-32-:sparc-:sun4-:sun4m-:sun4m- (tnx RDM)
+0.73: sunos-5.5-generic-:i386-:i86pc-:i86pc-:i86pc- (tnx PW)
+0.72: sunos-5.5-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx CG)
+0.73: sunos-5.5-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx RDM)
+0.72: sunos-5.5-generic-:sparc-:sun4-:sun4u-:sun4u- (tnx SAC)
+0.72: sunos-5.5-generic_103094-03-:i386-:i86pc-:i86pc-:i86pc- (tnx root@utahdining=???)
+0.73: sunos-5.5-generic_103094-07-:i386-:i86pc-:i86pc-:i86pc- (tnx MAZ)
+0.73: sunos-5.5.1-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx CG)
+0.73: sunos-5.5.1-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx MBS)
+0.73: sunos-5.5.1-generic_103640-03-:sparc-:sun4-:sun4m-:sun4m- (tnx DPS)
+0.72: sunos-5.5.1-generic_103640-03-:sparc-:sun4-:sun4u-:sun4u- (tnx root@adrastea=???)
+0.73: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4m-:sun4m- (tnx RA)
+0.72: sunos-5.5.1-generic_patch-:i386-:i86pc-:i86pc-:i86pc- (tnx D2K)
+0.73: sunos-5.5.1-iss_1.0-:sparc-:sun4-:sun4u-:sun4u- (tnx LST)
+0.73: sunos-5.6-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx DS)
+0.73: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (tnx DV)
+0.73: ultrix-4.3-0-:-:-:risc-:- (tnx bruno@cerberus=???)
+0.73: unix_sv-4.2mp-2.03-:i386-:-:i386-:- (tnx HP)
+0.73: unix_sv-4.2mp-2.1.2-:i386-:-:i386-:- (tnx RN)
diff --git a/SYSDEPS b/SYSDEPS
new file mode 100644
index 0000000..f855826
--- /dev/null
+++ b/SYSDEPS
@@ -0,0 +1,9 @@
+VERSION
+systype
+hassgact.h
+hassgprm.h
+haswaitp.h
+select.h
+dns.lib
+socket.lib
+uint32.h
diff --git a/TARGETS b/TARGETS
new file mode 100644
index 0000000..3ca5f8d
--- /dev/null
+++ b/TARGETS
@@ -0,0 +1,133 @@
+auto-ccld.sh
+make-load
+find-systype
+systype
+load
+make-compile
+compile
+tcpclient.o
+ip.o
+ipalloc.o
+dns.o
+remoteinfo.o
+select.h
+timeoutconn.o
+timeoutread.o
+timeoutwrite.o
+make-makelib
+makelib
+stralloc_eady.o
+stralloc_pend.o
+stralloc_copy.o
+stralloc_opys.o
+stralloc_opyb.o
+stralloc_cat.o
+stralloc_cats.o
+stralloc_catb.o
+stralloc.a
+env.o
+envread.o
+env.a
+alloc.o
+alloc_re.o
+alloc.a
+ndelay.o
+ndelay_off.o
+ndelay.a
+substdio.o
+substdi.o
+substdo.o
+subfderr.o
+subfdout.o
+subfdin.o
+substdio_copy.o
+substdio.a
+error.o
+error_str.o
+error.a
+str_len.o
+str_diff.o
+str_diffn.o
+str_cpy.o
+byte_chr.o
+byte_rchr.o
+byte_diff.o
+byte_copy.o
+byte_cr.o
+byte_zero.o
+str.a
+hassgprm.h
+sig_block.o
+hassgact.h
+sig_catch.o
+sig_pause.o
+sig_dfl.o
+sig_pipe.o
+sig_child.o
+sig_term.o
+sig.a
+fd_copy.o
+fd_move.o
+fd.a
+case_lowers.o
+case.a
+subgetopt.o
+sgetopt.o
+getopt.a
+fmt_str.o
+fmt_ulong.o
+scan_ulong.o
+scan_8long.o
+fs.a
+socket.lib
+dns.lib
+tcpclient
+uint32.h
+tcpserver.o
+cdb_hash.o
+cdb_unpack.o
+cdb_seek.o
+cdb.a
+open_read.o
+open_trunc.o
+open.a
+haswaitp.h
+wait_nohang.o
+wait.a
+strerr_sys.o
+strerr_die.o
+strerr.a
+tcpserver
+tcprules.o
+cdbmss.o
+cdbmake_pack.o
+cdbmake_hash.o
+cdbmake_add.o
+cdbmake.a
+getln.o
+getln2.o
+getln.a
+seek_cur.o
+seek_end.o
+seek_set.o
+seek_trunc.o
+seek.a
+tcprules
+who@
+date@
+finger@
+tcpcat
+mconnect
+addcr.o
+addcr
+delcr.o
+delcr
+it
+tcpclient.0
+tcpserver.0
+tcprules.0
+tcp-environ.0
+man
+install.o
+install
+setup
diff --git a/TCP b/TCP
new file mode 100644
index 0000000..1d31ca0
--- /dev/null
+++ b/TCP
@@ -0,0 +1,45 @@
+TCP UCSPI protocol definition
+Copyright 1996
+D. J. Bernstein, djb@pobox.com
+
+
+This document defines the TCP protocol for UCSPI-1996 tools. A TCP
+client communicates with a TCP server, on the same machine or on a
+different machine, via the TCP/IP protocol through an Internet-domain
+socket. The descriptors passed to a TCP UCSPI application are copies of
+that socket, dup()ed from a single connect() or accept().
+
+[address] consists of two arguments: [hostname] [port].
+
+There are three possibilities for [hostname]: the number 0, referring to
+the local host; a dotted-decimal IP address, such as 192.48.96.5; or a
+name understood by the system's resolver, such as mail.uu.net. TCP UCSPI
+servers use only the first IP address from the resolver; TCP UCSPI
+clients try each address in turn.
+
+There are three possibilities for [port]: a positive numeric TCP port
+number, such as 25; the number 0, which permits selection of any port
+number; or a name understood by the system's getservbyname(), such as
+smtp.
+
+The client and server set up the following environment variables:
+
+ PROTO: the string TCP
+ TCPLOCALIP: the dotted-decimal IP address of the local host
+ TCPLOCALPORT: the local TCP port number, in decimal
+ TCPREMOTEIP: the dotted-decimal IP address of the remote host
+ TCPREMOTEPORT: the remote TCP port number, in decimal
+ TCPLOCALHOST, if possible: the resolver's name for TCPLOCALIP
+ TCPREMOTEHOST, if possible: the resolver's name for TCPREMOTEIP
+ TCPREMOTEINFO, if possible: the result of a 931/1413/IDENT/TAP query
+
+Uppercase letters in TCPLOCALHOST and TCPREMOTEHOST are converted to
+lowercase. TCPREMOTEINFO is a connection-specific string supplied by the
+remote host via 931/1413/IDENT/TAP.
+
+TCP UCSPI tools take a -R option to turn off 931/1413/IDENT/TAP
+querying, and a -r option to turn it back on. TCP UCSPI clients take a
+-p [locport] option to require a particular TCP port on the local side
+of the connection. TCP UCSPI servers take a -1 option to print the local
+port number (in decimal, followed by a newline) to descriptor 1 before
+closing descriptor 1 and after preparing to receive connections.
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..4b5cbdd
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,62 @@
+Thanks to various people for bug reports and other comments on various
+versions of tcpclient, tcpserver, and tcpcontrol:
+
+RA = Russ Allbery
+J2B = Jos Backus
+JLB = Julie L. Baumler
+HB = Harald Barth
+WEB = William E. Baxter
+DEB = Donald E. Blais
+SAC = Shawn A. Clifford
+JJE = Joshua J. Ellis
+JF = Janos Farkas
+CG = Chris Garrigues
+BG = Bert Gijsbers
+TG = Tim Goodwin
+J2H = Jeff Hayward
+J1H = Johan Holmberg
+AI = Akihiro Iijima
+DJ = Dirk Jaeckel
+SJ = Sudish Joseph
+PMK = Patrick M. Kane
+D2K = Dax Kelson
+T2K = Thomas Kuerten
+GL = Giles Lean
+KL = Karl Lehenbauer
+FPL = Frederik P. Lindberg
+SML = Stefan M. Linnemann
+JL = Jim Littlefield
+RWL = Robert W. Luce
+RAL = Roberto A. Lumbreras
+TM = Toshinori Maeno
+TLM = Timothy L. Mayo
+RDM = Raul D. Miller
+JDM = John D. Mitchell
+NM = Nobuhiro Murata
+FN = Faried Nawaz
+RN = Russell Nelson
+SN = Stan Norton
+A2P = Andrea Paolini
+HP = Hitesh Patel
+GDP = Greg D. Patterson
+EAP = Eric A. Perlman
+BJR = Brian J. Reichert
+M1S = Michael Salmon
+MBS = Mike Scher
+AS = Amos Shapira
+DS = Dave Sill
+MPS = Matt P. Simerson
+DPS = David P. Smith
+RAS = Richard A. Soderberg
+LST = Louis S. Theran
+VV = Vince Vielhaber
+DV = Dirk Vluegels
+DMV = Dan M. Vogel
+AV = Alex Vostrikov
+EW = Erik Wallin
+CW = Christian Wettergren
+AW = Arne Wichmann
+PW = Peter Wilkinson
+J2W = Jeremy Wohl
+AY = Araki Yasuhiro
+MAZ = Matthew A. Zahorik
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..f064441
--- /dev/null
+++ b/TODO
@@ -0,0 +1,3 @@
+use strerr in tcpclient
+maybe include multitee in package
+include more clients
diff --git a/UCSPI b/UCSPI
new file mode 100644
index 0000000..07e6db4
--- /dev/null
+++ b/UCSPI
@@ -0,0 +1,131 @@
+UNIX Client-Server Program Interface, UCSPI-1996
+Copyright 1996
+D. J. Bernstein, djb@pobox.com
+
+
+1. Introduction
+
+This document describes the UNIX Client-Server Program Interface, UCSPI
+(ooks-pie), a command-line interface to client-server communications
+tools.
+
+UCSPI provides several benefits. First, the UCSPI interface is
+independent of the underlying communications medium; UCSPI applications
+don't even have to be recompiled as the Internet upgrades from IPv4 to
+IPv6. Second, UCSPI lets shell scripts take advantage of networking.
+Third, UCSPI clients and servers conventionally set up environment
+variables that display the local and remote addresses, so the
+information is readily available to applications and users.
+
+Here is the general UCSPI framework. An UCSPI tool is a program that
+understands how to talk to some communications medium. It sets up two
+descriptors and then invokes an UCSPI application, which can read from
+one descriptor and write to the other. Every communications medium
+provides reliable two-way full-duplex strictly ordered not necessarily
+timed stream communication. Some media may provide other types of
+communication, such as expedited (``out-of-band'') transmission, in
+which the stream is no longer ordered, but most UCSPI applications are
+medium-independent and do not rely on such features.
+
+
+2. Tools
+
+UCSPI tools are executable programs. They accept command lines in the
+following general format:
+
+ [tool] [options] [address] [application]
+
+Here [tool] is the name of the tool, [options] are zero or more option
+arguments, [address] is a protocol-specific address, and [application]
+is a user-specified program to run for each connection.
+
+[options] are processed by the getopt standard; thus an argument of --
+terminates [options]. [tool] supports three options to control how
+much information it prints to stderr:
+
+ -v all available messages
+ -Q all available error messages; no messages in case of success
+ -q no messages in any case
+
+The default is -Q; later arguments override earlier arguments. [tool]
+may support many further options.
+
+[application] consists of one or more arguments, handled by the
+conventions of execvp(). [tool] passes on all [application] arguments
+without change, no matter what characters appear in those arguments.
+
+[tool] always changes certain file descriptors, as described in section
+3, and environment variables, as described in section 4, before
+executing [application].
+
+[tool] might fork before executing [application], and it might reset
+some signals that were previously ignored. Other than this, [tool] does
+not change its process state before executing [application].
+
+[tool] does not assume that any particular descriptors are open or
+closed upon entry. [tool] does not force itself into the background; nor
+does it attempt to detach from a controlling terminal.
+
+If [tool] cannot perform its functions, it exits with a nonzero code.
+
+
+3. Clients and servers
+
+There are two types of UCSPI tools: clients and servers.
+
+An UCSPI client closes descriptors 6 and 7 and connects to a server at
+[address]. Upon connecting, it spawns [application] with descriptor 6
+reading from the connection and descriptor 7 writing to the connection.
+The client does not make any further connections. When [application]
+dies, the client dies; the client exits with a zero code if and only if
+[application] exited with a zero code.
+
+An UCSPI server closes descriptors 0 and 1 and waits for a client to
+connect to [address]. Upon accepting a connection, it spawns
+[application] with descriptor 0 reading from the connection and
+descriptor 1 writing to the connection. Meanwhile, and subsequently, it
+continues accepting connections to [address]. If the server receives
+signal SIGTERM, it exits with code 0; this does not affect any current
+connections.
+
+
+4. Protocols
+
+Each UCSPI tool supports a protocol. A protocol definition provides
+three pieces of information: the name of the protocol; the format and
+meaning of [address]; and the environment variables set up by the tool.
+
+A protocol name is a sequence of one or more alphanumeric characters.
+See section 5 for information about the allocation of protocol names.
+
+A protocol definition always states the number of arguments taken by
+[address] and the allowed form for each argument. It also states an
+underlying communications medium to be used by the tool, and gives the
+interpretation of [address] in terms of that medium.
+
+Each tool passes the following environment variables to [application]:
+PROTO=[PROTO], the name of the supported protocol; zero or more
+variables beginning with [PROTO]LOCAL, as stated in the protocol
+definition; and zero or more variables beginning with [PROTO]REMOTE, as
+stated in the protocol definition. For clients, [PROTO]LOCAL variables
+give information about the client, and [PROTO]REMOTE variables give
+information about the server; vice versa for servers.
+
+Protocol definitions may specify environment variables that, in some
+situations, are not set. Those variables might be set upon entry to an
+UCSPI tool; if so, they must be unset, not passed along.
+
+A protocol definition may impose further requirements on clients and
+servers, such as supported options, forking behavior, and the nature of
+the descriptors passed to [application].
+
+
+5. Protocol management
+
+Public protocol definitions may be registered with me. I may refuse a
+registration request on the grounds of a namespace problem, but in that
+case I will suggest an acceptable replacement name.
+
+Protocol names beginning with x will be parcelled out to organizations
+that would like to define their own protocols. Protocol names beginning
+with X are reserved for experimental use.
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..64c4d90
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+ucspi-tcp 0.80
diff --git a/addcr.c b/addcr.c
new file mode 100644
index 0000000..a452450
--- /dev/null
+++ b/addcr.c
@@ -0,0 +1,23 @@
+#include "substdio.h"
+#include "subfd.h"
+#include "exit.h"
+
+void main()
+{
+ register int n;
+ register char *x;
+ char ch;
+
+ for (;;) {
+ n = substdio_feed(subfdin);
+ if (n < 0) _exit(111);
+ if (!n) _exit(0);
+ x = substdio_PEEK(subfdin);
+ substdio_SEEK(subfdin,n);
+ while (n > 0) {
+ ch = *x++; --n;
+ if (ch == '\n') substdio_BPUTC(subfdout,"\r"[0]);
+ substdio_BPUTC(subfdout,ch);
+ }
+ }
+}
diff --git a/addcr=x b/addcr=x
new file mode 100644
index 0000000..f3e9229
--- /dev/null
+++ b/addcr=x
@@ -0,0 +1,3 @@
+substdio.a
+error.a
+str.a
diff --git a/alloc.c b/alloc.c
new file mode 100644
index 0000000..c661453
--- /dev/null
+++ b/alloc.c
@@ -0,0 +1,32 @@
+#include "alloc.h"
+#include "error.h"
+extern char *malloc();
+extern void free();
+
+#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */
+#define SPACE 4096 /* must be multiple of ALIGNMENT */
+
+typedef union { char irrelevant[ALIGNMENT]; double d; } aligned;
+static aligned realspace[SPACE / ALIGNMENT];
+#define space ((char *) realspace)
+static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */
+
+/*@null@*//*@out@*/char *alloc(n)
+unsigned int n;
+{
+ char *x;
+ n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */
+ if (n <= avail) { avail -= n; return space + avail; }
+ x = malloc(n);
+ if (!x) errno = error_nomem;
+ return x;
+}
+
+void alloc_free(x)
+char *x;
+{
+ if (x >= space)
+ if (x < space + SPACE)
+ return; /* XXX: assuming that pointers are flat */
+ free(x);
+}
diff --git a/alloc.h b/alloc.h
new file mode 100644
index 0000000..1b1d893
--- /dev/null
+++ b/alloc.h
@@ -0,0 +1,8 @@
+#ifndef ALLOC_H
+#define ALLOC_H
+
+extern /*@null@*//*@out@*/char *alloc();
+extern void alloc_free();
+extern int alloc_re();
+
+#endif
diff --git a/alloc=l b/alloc=l
new file mode 100644
index 0000000..6dc62ab
--- /dev/null
+++ b/alloc=l
@@ -0,0 +1,2 @@
+alloc.o
+alloc_re.o
diff --git a/alloc_re.c b/alloc_re.c
new file mode 100644
index 0000000..feb8b49
--- /dev/null
+++ b/alloc_re.c
@@ -0,0 +1,17 @@
+#include "alloc.h"
+#include "byte.h"
+
+int alloc_re(x,m,n)
+char **x;
+unsigned int m;
+unsigned int n;
+{
+ char *y;
+
+ y = alloc(n);
+ if (!y) return 0;
+ byte_copy(y,m,*x);
+ alloc_free(*x);
+ *x = y;
+ return 1;
+}
diff --git a/auto-str.c b/auto-str.c
new file mode 100644
index 0000000..acc3d60
--- /dev/null
+++ b/auto-str.c
@@ -0,0 +1,44 @@
+#include "substdio.h"
+#include "readwrite.h"
+#include "exit.h"
+
+char buf1[256];
+substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1));
+
+void puts(s)
+char *s;
+{
+ if (substdio_puts(&ss1,s) == -1) _exit(111);
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+ char *name;
+ char *value;
+ unsigned char ch;
+ char octal[4];
+
+ name = argv[1];
+ if (!name) _exit(100);
+ value = argv[2];
+ if (!value) _exit(100);
+
+ puts("char ");
+ puts(name);
+ puts("[] = \"\\\n");
+
+ while (ch = *value++) {
+ puts("\\");
+ octal[3] = 0;
+ octal[2] = '0' + (ch & 7); ch >>= 3;
+ octal[1] = '0' + (ch & 7); ch >>= 3;
+ octal[0] = '0' + (ch & 7);
+ puts(octal);
+ }
+
+ puts("\\\n\";\n");
+ if (substdio_flush(&ss1) == -1) _exit(111);
+ _exit(0);
+}
diff --git a/auto-str=x b/auto-str=x
new file mode 100644
index 0000000..f3e9229
--- /dev/null
+++ b/auto-str=x
@@ -0,0 +1,3 @@
+substdio.a
+error.a
+str.a
diff --git a/byte.h b/byte.h
new file mode 100644
index 0000000..de06c69
--- /dev/null
+++ b/byte.h
@@ -0,0 +1,13 @@
+#ifndef BYTE_H
+#define BYTE_H
+
+extern unsigned int byte_chr();
+extern unsigned int byte_rchr();
+extern void byte_copy();
+extern void byte_copyr();
+extern int byte_diff();
+extern void byte_zero();
+
+#define byte_equal(s,n,t) (!byte_diff((s),(n),(t)))
+
+#endif
diff --git a/byte_chr.c b/byte_chr.c
new file mode 100644
index 0000000..f81dde8
--- /dev/null
+++ b/byte_chr.c
@@ -0,0 +1,20 @@
+#include "byte.h"
+
+unsigned int byte_chr(s,n,c)
+char *s;
+register unsigned int n;
+int c;
+{
+ register char ch;
+ register char *t;
+
+ ch = c;
+ t = s;
+ for (;;) {
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ }
+ return t - s;
+}
diff --git a/byte_copy.c b/byte_copy.c
new file mode 100644
index 0000000..eaad11b
--- /dev/null
+++ b/byte_copy.c
@@ -0,0 +1,14 @@
+#include "byte.h"
+
+void byte_copy(to,n,from)
+register char *to;
+register unsigned int n;
+register char *from;
+{
+ for (;;) {
+ if (!n) return; *to++ = *from++; --n;
+ if (!n) return; *to++ = *from++; --n;
+ if (!n) return; *to++ = *from++; --n;
+ if (!n) return; *to++ = *from++; --n;
+ }
+}
diff --git a/byte_cr.c b/byte_cr.c
new file mode 100644
index 0000000..3e7a1d5
--- /dev/null
+++ b/byte_cr.c
@@ -0,0 +1,16 @@
+#include "byte.h"
+
+void byte_copyr(to,n,from)
+register char *to;
+register unsigned int n;
+register char *from;
+{
+ to += n;
+ from += n;
+ for (;;) {
+ if (!n) return; *--to = *--from; --n;
+ if (!n) return; *--to = *--from; --n;
+ if (!n) return; *--to = *--from; --n;
+ if (!n) return; *--to = *--from; --n;
+ }
+}
diff --git a/byte_diff.c b/byte_diff.c
new file mode 100644
index 0000000..cdbd760
--- /dev/null
+++ b/byte_diff.c
@@ -0,0 +1,16 @@
+#include "byte.h"
+
+int byte_diff(s,n,t)
+register char *s;
+register unsigned int n;
+register char *t;
+{
+ for (;;) {
+ if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+ if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+ if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+ if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+ }
+ return ((int)(unsigned int)(unsigned char) *s)
+ - ((int)(unsigned int)(unsigned char) *t);
+}
diff --git a/byte_rchr.c b/byte_rchr.c
new file mode 100644
index 0000000..476bc22
--- /dev/null
+++ b/byte_rchr.c
@@ -0,0 +1,23 @@
+#include "byte.h"
+
+unsigned int byte_rchr(s,n,c)
+char *s;
+register unsigned int n;
+int c;
+{
+ register char ch;
+ register char *t;
+ register char *u;
+
+ ch = c;
+ t = s;
+ u = 0;
+ for (;;) {
+ if (!n) break; if (*t == ch) u = t; ++t; --n;
+ if (!n) break; if (*t == ch) u = t; ++t; --n;
+ if (!n) break; if (*t == ch) u = t; ++t; --n;
+ if (!n) break; if (*t == ch) u = t; ++t; --n;
+ }
+ if (!u) u = t;
+ return u - s;
+}
diff --git a/byte_zero.c b/byte_zero.c
new file mode 100644
index 0000000..92009ba
--- /dev/null
+++ b/byte_zero.c
@@ -0,0 +1,13 @@
+#include "byte.h"
+
+void byte_zero(s,n)
+char *s;
+register unsigned int n;
+{
+ for (;;) {
+ if (!n) break; *s++ = 0; --n;
+ if (!n) break; *s++ = 0; --n;
+ if (!n) break; *s++ = 0; --n;
+ if (!n) break; *s++ = 0; --n;
+ }
+}
diff --git a/case.h b/case.h
new file mode 100644
index 0000000..35a2434
--- /dev/null
+++ b/case.h
@@ -0,0 +1,13 @@
+#ifndef CASE_H
+#define CASE_H
+
+extern void case_lowers();
+extern void case_lowerb();
+extern int case_diffs();
+extern int case_diffb();
+extern int case_starts();
+extern int case_startb();
+
+#define case_equals(s,t) (!case_diffs((s),(t)))
+
+#endif
diff --git a/case=l b/case=l
new file mode 100644
index 0000000..92782ab
--- /dev/null
+++ b/case=l
@@ -0,0 +1 @@
+case_lowers.o
diff --git a/case_lowers.c b/case_lowers.c
new file mode 100644
index 0000000..208b3f5
--- /dev/null
+++ b/case_lowers.c
@@ -0,0 +1,12 @@
+#include "case.h"
+
+void case_lowers(s)
+char *s;
+{
+ unsigned char x;
+ while (x = *s) {
+ x -= 'A';
+ if (x <= 'Z' - 'A') *s = x + 'a';
+ ++s;
+ }
+}
diff --git a/cdb.h b/cdb.h
new file mode 100644
index 0000000..571e5d6
--- /dev/null
+++ b/cdb.h
@@ -0,0 +1,12 @@
+#ifndef CDB_H
+#define CDB_H
+
+#include "uint32.h"
+
+extern uint32 cdb_hash();
+extern uint32 cdb_unpack();
+
+extern int cdb_bread();
+extern int cdb_seek();
+
+#endif
diff --git a/cdb=l b/cdb=l
new file mode 100644
index 0000000..fef0e62
--- /dev/null
+++ b/cdb=l
@@ -0,0 +1,3 @@
+cdb_hash.o
+cdb_unpack.o
+cdb_seek.o
diff --git a/cdb_hash.c b/cdb_hash.c
new file mode 100644
index 0000000..8238020
--- /dev/null
+++ b/cdb_hash.c
@@ -0,0 +1,16 @@
+#include "cdb.h"
+
+uint32 cdb_hash(buf,len)
+unsigned char *buf;
+unsigned int len;
+{
+ uint32 h;
+
+ h = 5381;
+ while (len) {
+ --len;
+ h += (h << 5);
+ h ^= (uint32) *buf++;
+ }
+ return h;
+}
diff --git a/cdb_seek.c b/cdb_seek.c
new file mode 100644
index 0000000..87ab614
--- /dev/null
+++ b/cdb_seek.c
@@ -0,0 +1,95 @@
+#include <sys/types.h>
+#include <errno.h>
+extern int errno;
+#include "cdb.h"
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+int cdb_bread(fd,buf,len)
+int fd;
+char *buf;
+int len;
+{
+ int r;
+ while (len > 0) {
+ do
+ r = read(fd,buf,len);
+ while ((r == -1) && (errno == EINTR));
+ if (r == -1) return -1;
+ if (r == 0) { errno = EIO; return -1; }
+ buf += r;
+ len -= r;
+ }
+ return 0;
+}
+
+static int match(fd,key,len)
+int fd;
+char *key;
+unsigned int len;
+{
+ char buf[32];
+ int n;
+ int i;
+
+ while (len > 0) {
+ n = sizeof(buf);
+ if (n > len) n = len;
+ if (cdb_bread(fd,buf,n) == -1) return -1;
+ for (i = 0;i < n;++i) if (buf[i] != key[i]) return 0;
+ key += n;
+ len -= n;
+ }
+ return 1;
+}
+
+int cdb_seek(fd,key,len,dlen)
+int fd;
+char *key;
+unsigned int len;
+uint32 *dlen;
+{
+ char packbuf[8];
+ uint32 pos;
+ uint32 h;
+ uint32 lenhash;
+ uint32 h2;
+ uint32 loop;
+ uint32 poskd;
+
+ h = cdb_hash(key,len);
+
+ pos = 8 * (h & 255);
+ if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1;
+
+ if (cdb_bread(fd,packbuf,8) == -1) return -1;
+
+ pos = cdb_unpack(packbuf);
+ lenhash = cdb_unpack(packbuf + 4);
+
+ if (!lenhash) return 0;
+ h2 = (h >> 8) % lenhash;
+
+ for (loop = 0;loop < lenhash;++loop) {
+ if (lseek(fd,(off_t) (pos + 8 * h2),SEEK_SET) == -1) return -1;
+ if (cdb_bread(fd,packbuf,8) == -1) return -1;
+ poskd = cdb_unpack(packbuf + 4);
+ if (!poskd) return 0;
+ if (cdb_unpack(packbuf) == h) {
+ if (lseek(fd,(off_t) poskd,SEEK_SET) == -1) return -1;
+ if (cdb_bread(fd,packbuf,8) == -1) return -1;
+ if (cdb_unpack(packbuf) == len)
+ switch(match(fd,key,len)) {
+ case -1:
+ return -1;
+ case 1:
+ *dlen = cdb_unpack(packbuf + 4);
+ return 1;
+ }
+ }
+ if (++h2 == lenhash) h2 = 0;
+ }
+ return 0;
+}
diff --git a/cdb_unpack.c b/cdb_unpack.c
new file mode 100644
index 0000000..c882202
--- /dev/null
+++ b/cdb_unpack.c
@@ -0,0 +1,12 @@
+#include "cdb.h"
+
+uint32 cdb_unpack(buf)
+unsigned char *buf;
+{
+ uint32 num;
+ num = buf[3]; num <<= 8;
+ num += buf[2]; num <<= 8;
+ num += buf[1]; num <<= 8;
+ num += buf[0];
+ return num;
+}
diff --git a/cdbmake.h b/cdbmake.h
new file mode 100644
index 0000000..883a231
--- /dev/null
+++ b/cdbmake.h
@@ -0,0 +1,35 @@
+#ifndef CDBMAKE_H
+#define CDBMAKE_H
+
+#include "uint32.h"
+
+#define CDBMAKE_HPLIST 1000
+
+struct cdbmake_hp { uint32 h; uint32 p; } ;
+
+struct cdbmake_hplist {
+ struct cdbmake_hp hp[CDBMAKE_HPLIST];
+ struct cdbmake_hplist *next;
+ int num;
+} ;
+
+struct cdbmake {
+ char final[2048];
+ uint32 count[256];
+ uint32 start[256];
+ struct cdbmake_hplist *head;
+ struct cdbmake_hp *split; /* includes space for hash */
+ struct cdbmake_hp *hash;
+ uint32 numentries;
+} ;
+
+extern void cdbmake_pack();
+#define CDBMAKE_HASHSTART ((uint32) 5381)
+extern uint32 cdbmake_hashadd();
+
+extern void cdbmake_init();
+extern int cdbmake_add();
+extern int cdbmake_split();
+extern uint32 cdbmake_throw();
+
+#endif
diff --git a/cdbmake=l b/cdbmake=l
new file mode 100644
index 0000000..5747fb0
--- /dev/null
+++ b/cdbmake=l
@@ -0,0 +1,3 @@
+cdbmake_pack.o
+cdbmake_hash.o
+cdbmake_add.o
diff --git a/cdbmake_add.c b/cdbmake_add.c
new file mode 100644
index 0000000..115f828
--- /dev/null
+++ b/cdbmake_add.c
@@ -0,0 +1,117 @@
+#include "cdbmake.h"
+
+void cdbmake_init(cdbm)
+struct cdbmake *cdbm;
+{
+ cdbm->head = 0;
+ cdbm->split = 0;
+ cdbm->hash = 0;
+ cdbm->numentries = 0;
+}
+
+int cdbmake_add(cdbm,h,p,alloc)
+struct cdbmake *cdbm;
+uint32 h;
+uint32 p;
+char *(*alloc)();
+{
+ struct cdbmake_hplist *head;
+
+ head = cdbm->head;
+ if (!head || (head->num >= CDBMAKE_HPLIST)) {
+ head = (struct cdbmake_hplist *) alloc(sizeof(struct cdbmake_hplist));
+ if (!head) return 0;
+ head->num = 0;
+ head->next = cdbm->head;
+ cdbm->head = head;
+ }
+ head->hp[head->num].h = h;
+ head->hp[head->num].p = p;
+ ++head->num;
+ ++cdbm->numentries;
+ return 1;
+}
+
+int cdbmake_split(cdbm,alloc)
+struct cdbmake *cdbm;
+char *(*alloc)();
+{
+ int i;
+ uint32 u;
+ uint32 memsize;
+ struct cdbmake_hplist *x;
+
+ for (i = 0;i < 256;++i)
+ cdbm->count[i] = 0;
+
+ for (x = cdbm->head;x;x = x->next) {
+ i = x->num;
+ while (i--)
+ ++cdbm->count[255 & x->hp[i].h];
+ }
+
+ memsize = 1;
+ for (i = 0;i < 256;++i) {
+ u = cdbm->count[i] * 2;
+ if (u > memsize)
+ memsize = u;
+ }
+
+ memsize += cdbm->numentries; /* no overflow possible up to now */
+ u = (uint32) 0 - (uint32) 1;
+ u /= sizeof(struct cdbmake_hp);
+ if (memsize > u) return 0;
+
+ cdbm->split = (struct cdbmake_hp *) alloc(memsize * sizeof(struct cdbmake_hp));
+ if (!cdbm->split) return 0;
+
+ cdbm->hash = cdbm->split + cdbm->numentries;
+
+ u = 0;
+ for (i = 0;i < 256;++i) {
+ u += cdbm->count[i]; /* bounded by numentries, so no overflow */
+ cdbm->start[i] = u;
+ }
+
+ for (x = cdbm->head;x;x = x->next) {
+ i = x->num;
+ while (i--)
+ cdbm->split[--cdbm->start[255 & x->hp[i].h]] = x->hp[i];
+ }
+
+ return 1;
+}
+
+uint32 cdbmake_throw(cdbm,pos,b)
+struct cdbmake *cdbm;
+uint32 pos;
+int b;
+{
+ uint32 len;
+ uint32 j;
+ uint32 count;
+ struct cdbmake_hp *hp;
+ uint32 where;
+
+ count = cdbm->count[b];
+
+ len = count + count; /* no overflow possible */
+ cdbmake_pack(cdbm->final + 8 * b,pos);
+ cdbmake_pack(cdbm->final + 8 * b + 4,len);
+
+ if (len) {
+ for (j = 0;j < len;++j)
+ cdbm->hash[j].h = cdbm->hash[j].p = 0;
+
+ hp = cdbm->split + cdbm->start[b];
+ for (j = 0;j < count;++j) {
+ where = (hp->h >> 8) % len;
+ while (cdbm->hash[where].p)
+ if (++where == len)
+ where = 0;
+ cdbm->hash[where] = *hp++;
+ }
+ }
+
+ return len;
+}
diff --git a/cdbmake_hash.c b/cdbmake_hash.c
new file mode 100644
index 0000000..f9dc3e5
--- /dev/null
+++ b/cdbmake_hash.c
@@ -0,0 +1,10 @@
+#include "cdbmake.h"
+
+uint32 cdbmake_hashadd(h,c)
+uint32 h;
+unsigned int c;
+{
+ h += (h << 5);
+ h ^= (uint32) (unsigned char) c;
+ return h;
+}
diff --git a/cdbmake_pack.c b/cdbmake_pack.c
new file mode 100644
index 0000000..04b5f5b
--- /dev/null
+++ b/cdbmake_pack.c
@@ -0,0 +1,11 @@
+#include "cdbmake.h"
+
+void cdbmake_pack(buf,num)
+unsigned char *buf;
+uint32 num;
+{
+ *buf++ = num; num >>= 8;
+ *buf++ = num; num >>= 8;
+ *buf++ = num; num >>= 8;
+ *buf = num;
+}
diff --git a/cdbmss.c b/cdbmss.c
new file mode 100644
index 0000000..2d8f367
--- /dev/null
+++ b/cdbmss.c
@@ -0,0 +1,65 @@
+#include "readwrite.h"
+#include "seek.h"
+#include "alloc.h"
+#include "cdbmss.h"
+
+int cdbmss_start(c,fd)
+struct cdbmss *c;
+int fd;
+{
+ cdbmake_init(&c->cdbm);
+ c->fd = fd;
+ c->pos = sizeof(c->cdbm.final);
+ substdio_fdbuf(&c->ss,write,fd,c->ssbuf,sizeof(c->ssbuf));
+ return seek_set(fd,(seek_pos) c->pos);
+}
+
+int cdbmss_add(c,key,keylen,data,datalen)
+struct cdbmss *c;
+unsigned char *key;
+unsigned int keylen;
+unsigned char *data;
+unsigned int datalen;
+{
+ uint32 h;
+ int i;
+
+ cdbmake_pack(c->packbuf,(uint32) keylen);
+ cdbmake_pack(c->packbuf + 4,(uint32) datalen);
+ if (substdio_put(&c->ss,c->packbuf,8) == -1) return -1;
+ if (substdio_put(&c->ss,key,keylen) == -1) return -1;
+ if (substdio_put(&c->ss,data,datalen) == -1) return -1;
+
+ h = CDBMAKE_HASHSTART;
+ for (i = 0;i < keylen;++i)
+ h = cdbmake_hashadd(h,(unsigned int) key[i]);
+
+ if (!cdbmake_add(&c->cdbm,h,c->pos,alloc)) return -1;
+
+ c->pos += 8 + keylen + datalen; /* XXX: overflow? */
+ return 0;
+}
+
+int cdbmss_finish(c)
+struct cdbmss *c;
+{
+ int i;
+ uint32 len;
+ uint32 u;
+
+ if (!cdbmake_split(&c->cdbm,alloc)) return -1;
+
+ for (i = 0;i < 256;++i) {
+ len = cdbmake_throw(&c->cdbm,c->pos,i);
+ for (u = 0;u < len;++u) {
+ cdbmake_pack(c->packbuf,c->cdbm.hash[u].h);
+ cdbmake_pack(c->packbuf + 4,c->cdbm.hash[u].p);
+ if (substdio_put(&c->ss,c->packbuf,8) == -1) return -1;
+ c->pos += 8; /* XXX: overflow? */
+ }
+ }
+
+ if (substdio_flush(&c->ss) == -1) return -1;
+ if (seek_begin(c->fd) == -1) return -1;
+ return substdio_putflush(&c->ss,c->cdbm.final,sizeof(c->cdbm.final));
+}
diff --git a/cdbmss.h b/cdbmss.h
new file mode 100644
index 0000000..5e6bdf4
--- /dev/null
+++ b/cdbmss.h
@@ -0,0 +1,16 @@
+#ifndef CDBMSS_H
+#define CDBMSS_H
+
+#include "cdbmake.h"
+#include "substdio.h"
+
+struct cdbmss {
+ char ssbuf[1024];
+ struct cdbmake cdbm;
+ substdio ss;
+ char packbuf[8];
+ uint32 pos;
+ int fd;
+} ;
+
+#endif
diff --git a/conf-bin b/conf-bin
new file mode 100644
index 0000000..d1fe68e
--- /dev/null
+++ b/conf-bin
@@ -0,0 +1,3 @@
+/usr/local/bin
+
+Programs will be installed in this directory.
diff --git a/conf-cc b/conf-cc
new file mode 100644
index 0000000..e58fb9b
--- /dev/null
+++ b/conf-cc
@@ -0,0 +1,3 @@
+cc -O2
+
+This will be used to compile .c files.
diff --git a/conf-ld b/conf-ld
new file mode 100644
index 0000000..a9e796a
--- /dev/null
+++ b/conf-ld
@@ -0,0 +1,3 @@
+cc -s
+
+This will be used to link .o files into an executable.
diff --git a/conf-man b/conf-man
new file mode 100644
index 0000000..b4e70a4
--- /dev/null
+++ b/conf-man
@@ -0,0 +1,5 @@
+/usr/local/man
+
+Man pages will be installed in subdirectories of this directory. An
+unformatted man page foo.1 will go into .../man1/foo.1; a formatted man
+page foo.0 will go into .../cat1/foo.0.
diff --git a/date@.sh b/date@.sh
new file mode 100644
index 0000000..80bfe5d
--- /dev/null
+++ b/date@.sh
@@ -0,0 +1 @@
+BIN/tcpclient -RHl0 -- "${1-0}" 13 sh -c 'exec BIN/delcr <&6' | cat -v
diff --git a/date@=s b/date@=s
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/date@=s
diff --git a/default.0.do b/default.0.do
new file mode 100644
index 0000000..e40b50c
--- /dev/null
+++ b/default.0.do
@@ -0,0 +1,9 @@
+if test -r "$2=0"
+then
+ dependon "$2=0"
+ dependon `cat "$2=0"`
+ nroff -man `cat "$2=0"`
+ formake nroff -man `cat "$2=0"` '>' $1
+else
+ nosuchtarget
+fi
diff --git a/default.a.do b/default.a.do
new file mode 100644
index 0000000..b61fc5c
--- /dev/null
+++ b/default.a.do
@@ -0,0 +1,10 @@
+if test -r "$2=l"
+then
+ dependon "$2=l"
+ dependon makelib `cat "$2=l"`
+ directtarget
+ formake ./makelib $1 `cat "$2=l"`
+ ./makelib $1 `cat "$2=l"`
+else
+ nosuchtarget
+fi
diff --git a/default.do b/default.do
new file mode 100644
index 0000000..6fe9f16
--- /dev/null
+++ b/default.do
@@ -0,0 +1,77 @@
+if test -r $1=x
+then
+ dependon $1=x
+ libs=`grep '\.lib *$' "$1=x"`
+ libscat=''
+ for i in $libs
+ do
+ libscat="$libscat "'`'"cat $i"'`'
+ done
+ objs=`grep -v '\.lib *$' "$1=x"`
+ dependon load $1.o $objs $libs
+ directtarget
+ formake ./load $1 $objs "$libscat"
+ eval ./load $1 $objs $libscat
+ exit 0
+fi
+
+if test -r $1=s
+then
+ dependon $1=s warn-auto.sh $1.sh conf-bin
+ formake cat warn-auto.sh $1.sh '\'
+ formake '| sed s}BIN}"`head -1 conf-bin`"}g >' $1
+ formake chmod 755 $1
+ cat warn-auto.sh $1.sh | sed s}BIN}"`head -1 conf-bin`"}g
+ chmod 755 $3
+ exit 0
+fi
+
+case "$1" in
+ shar)
+ dependon FILES `cat FILES`
+ formake 'shar -m `cat FILES` > shar'
+ formake 'chmod 400 shar'
+ shar -m `cat FILES`
+ chmod 400 $3
+ ;;
+ compile|load|makelib)
+ dependon make-$1 warn-auto.sh systype
+ formake "( cat warn-auto.sh; ./make-$1 "'"`cat systype`"'" ) > $1"
+ formake "chmod 755 $1"
+ cat warn-auto.sh
+ ./make-$1 "`cat systype`"
+ chmod 755 $3
+ ;;
+ make-compile|make-load|make-makelib)
+ dependon $1.sh auto-ccld.sh
+ formake "cat auto-ccld.sh $1.sh > $1"
+ formake "chmod 755 $1"
+ cat auto-ccld.sh $1.sh
+ chmod 755 $3
+ ;;
+ systype)
+ dependon find-systype trycpp.c
+ formake './find-systype > systype'
+ ./find-systype
+ ;;
+ find-systype)
+ dependon find-systype.sh auto-ccld.sh
+ formake 'cat auto-ccld.sh find-systype.sh > find-systype'
+ formake 'chmod 755 find-systype'
+ cat auto-ccld.sh find-systype.sh
+ chmod 755 $3
+ ;;
+ auto-ccld.sh)
+ dependon conf-cc conf-ld warn-auto.sh
+ formake '( cat warn-auto.sh; \'
+ formake 'echo CC=\'\''`head -1 conf-cc`\'\''; \'
+ formake 'echo LD=\'\''`head -1 conf-ld`\'\'' \'
+ formake ') > auto-ccld.sh'
+ cat warn-auto.sh
+ echo CC=\'`head -1 conf-cc`\'
+ echo LD=\'`head -1 conf-ld`\'
+ ;;
+ *)
+ nosuchtarget
+ ;;
+esac
diff --git a/default.o.do b/default.o.do
new file mode 100644
index 0000000..5d5ee1e
--- /dev/null
+++ b/default.o.do
@@ -0,0 +1,15 @@
+if test -r $2=m
+then
+ dependon $2=m $2.s
+ directtarget
+ as -o $1 $2.s
+ formake as -o $1 $2.s
+ exit 0
+fi
+depend -$2=m
+
+directtarget
+dependon compile
+dependcc $2.c
+formake ./compile $2.c
+./compile $2.c
diff --git a/delcr.c b/delcr.c
new file mode 100644
index 0000000..09b9ff3
--- /dev/null
+++ b/delcr.c
@@ -0,0 +1,37 @@
+#include "substdio.h"
+#include "subfd.h"
+#include "exit.h"
+
+void main()
+{
+ register int n;
+ register char *x;
+ char ch;
+ register int flagcr = 0;
+
+ for (;;) {
+ n = substdio_feed(subfdin);
+ if (n < 0) _exit(111);
+ if (!n) {
+ if (flagcr) substdio_BPUTC(subfdout,"\r"[0]);
+ _exit(0);
+ }
+ x = substdio_PEEK(subfdin);
+ substdio_SEEK(subfdin,n);
+
+ while (n > 0) {
+ ch = *x++; --n;
+ if (!flagcr) {
+ if (ch == '\r') { flagcr = 1; continue; }
+ substdio_BPUTC(subfdout,ch);
+ continue;
+ }
+ if (ch != '\n') {
+ substdio_BPUTC(subfdout,"\r"[0]);
+ if (ch == '\r') continue;
+ }
+ flagcr = 0;
+ substdio_BPUTC(subfdout,ch);
+ }
+ }
+}
diff --git a/delcr=x b/delcr=x
new file mode 100644
index 0000000..f3e9229
--- /dev/null
+++ b/delcr=x
@@ -0,0 +1,3 @@
+substdio.a
+error.a
+str.a
diff --git a/dns.c b/dns.c
new file mode 100644
index 0000000..bbb9770
--- /dev/null
+++ b/dns.c
@@ -0,0 +1,402 @@
+#include <stdio.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <errno.h>
+extern int res_query();
+extern int res_search();
+extern int errno;
+extern int h_errno;
+#include "ip.h"
+#include "ipalloc.h"
+#include "fmt.h"
+#include "alloc.h"
+#include "str.h"
+#include "stralloc.h"
+#include "dns.h"
+#include "case.h"
+
+static unsigned short getshort(c) unsigned char *c;
+{ unsigned short u; u = c[0]; return (u << 8) + c[1]; }
+
+static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response;
+static int responselen;
+static unsigned char *responseend;
+static unsigned char *responsepos;
+
+static int numanswers;
+static char name[MAXDNAME];
+static struct ip_address ip;
+unsigned short pref;
+
+static stralloc glue = {0};
+
+static int (*lookup)() = res_query;
+
+static int resolve(domain,type)
+stralloc *domain;
+int type;
+{
+ int n;
+ int i;
+
+ errno = 0;
+ if (!stralloc_copy(&glue,domain)) return DNS_MEM;
+ if (!stralloc_0(&glue)) return DNS_MEM;
+ responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response));
+ if (responselen <= 0)
+ {
+ if (errno == ECONNREFUSED) return DNS_SOFT;
+ if (h_errno == TRY_AGAIN) return DNS_SOFT;
+ return DNS_HARD;
+ }
+ if (responselen >= sizeof(response))
+ responselen = sizeof(response);
+ responseend = response.buf + responselen;
+ responsepos = response.buf + sizeof(HEADER);
+ n = ntohs(response.hdr.qdcount);
+ while (n-- > 0)
+ {
+ i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
+ if (i < 0) return DNS_SOFT;
+ responsepos += i;
+ i = responseend - responsepos;
+ if (i < QFIXEDSZ) return DNS_SOFT;
+ responsepos += QFIXEDSZ;
+ }
+ numanswers = ntohs(response.hdr.ancount);
+ return 0;
+}
+
+static int findname(wanttype)
+int wanttype;
+{
+ unsigned short rrtype;
+ unsigned short rrdlen;
+ int i;
+
+ if (numanswers <= 0) return 2;
+ --numanswers;
+ if (responsepos == responseend) return DNS_SOFT;
+
+ i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
+ if (i < 0) return DNS_SOFT;
+ responsepos += i;
+
+ i = responseend - responsepos;
+ if (i < 4 + 3 * 2) return DNS_SOFT;
+
+ rrtype = getshort(responsepos);
+ rrdlen = getshort(responsepos + 8);
+ responsepos += 10;
+
+ if (rrtype == wanttype)
+ {
+ if (dn_expand(response.buf,responseend,responsepos,name,MAXDNAME) < 0)
+ return DNS_SOFT;
+ responsepos += rrdlen;
+ return 1;
+ }
+
+ responsepos += rrdlen;
+ return 0;
+}
+
+static int findip(wanttype)
+int wanttype;
+{
+ unsigned short rrtype;
+ unsigned short rrdlen;
+ int i;
+
+ if (numanswers <= 0) return 2;
+ --numanswers;
+ if (responsepos == responseend) return DNS_SOFT;
+
+ i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
+ if (i < 0) return DNS_SOFT;
+ responsepos += i;
+
+ i = responseend - responsepos;
+ if (i < 4 + 3 * 2) return DNS_SOFT;
+
+ rrtype = getshort(responsepos);
+ rrdlen = getshort(responsepos + 8);
+ responsepos += 10;
+
+ if (rrtype == wanttype)
+ {
+ if (rrdlen < 4)
+ return DNS_SOFT;
+ ip.d[0] = responsepos[0];
+ ip.d[1] = responsepos[1];
+ ip.d[2] = responsepos[2];
+ ip.d[3] = responsepos[3];
+ responsepos += rrdlen;
+ return 1;
+ }
+
+ responsepos += rrdlen;
+ return 0;
+}
+
+static int findmx(wanttype)
+int wanttype;
+{
+ unsigned short rrtype;
+ unsigned short rrdlen;
+ int i;
+
+ if (numanswers <= 0) return 2;
+ --numanswers;
+ if (responsepos == responseend) return DNS_SOFT;
+
+ i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
+ if (i < 0) return DNS_SOFT;
+ responsepos += i;
+
+ i = responseend - responsepos;
+ if (i < 4 + 3 * 2) return DNS_SOFT;
+
+ rrtype = getshort(responsepos);
+ rrdlen = getshort(responsepos + 8);
+ responsepos += 10;
+
+ if (rrtype == wanttype)
+ {
+ if (rrdlen < 3)
+ return DNS_SOFT;
+ pref = (responsepos[0] << 8) + responsepos[1];
+ if (dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0)
+ return DNS_SOFT;
+ responsepos += rrdlen;
+ return 1;
+ }
+
+ responsepos += rrdlen;
+ return 0;
+}
+
+void dns_init(flagsearch)
+int flagsearch;
+{
+ res_init();
+ if (flagsearch) lookup = res_search;
+}
+
+int dns_cname(sa)
+stralloc *sa;
+{
+ int r;
+ int loop;
+ for (loop = 0;loop < 10;++loop)
+ {
+ if (!sa->len) return loop;
+ if (sa->s[sa->len - 1] == ']') return loop;
+ if (sa->s[sa->len - 1] == '.') { --sa->len; continue; }
+ switch(resolve(sa,T_ANY))
+ {
+ case DNS_MEM: return DNS_MEM;
+ case DNS_SOFT: return DNS_SOFT;
+ case DNS_HARD: return loop;
+ default:
+ while ((r = findname(T_CNAME)) != 2)
+ {
+ if (r == DNS_SOFT) return DNS_SOFT;
+ if (r == 1)
+ {
+ if (!stralloc_copys(sa,name)) return DNS_MEM;
+ break;
+ }
+ }
+ if (r == 2) return loop;
+ }
+ }
+ return DNS_HARD; /* alias loop */
+}
+
+#define FMT_IAA 40
+
+static int iaafmt(s,ip)
+char *s;
+struct ip_address *ip;
+{
+ unsigned int i;
+ unsigned int len;
+ len = 0;
+ i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i;
+ i = fmt_str(s,"."); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i;
+ i = fmt_str(s,"."); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i;
+ i = fmt_str(s,"."); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i;
+ i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i;
+ return len;
+}
+
+int dns_ptr(sa,ip)
+stralloc *sa;
+struct ip_address *ip;
+{
+ int r;
+
+ if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM;
+ sa->len = iaafmt(sa->s,ip);
+ switch(resolve(sa,T_PTR))
+ {
+ case DNS_MEM: return DNS_MEM;
+ case DNS_SOFT: return DNS_SOFT;
+ case DNS_HARD: return DNS_HARD;
+ }
+ while ((r = findname(T_PTR)) != 2)
+ {
+ if (r == DNS_SOFT) return DNS_SOFT;
+ if (r == 1)
+ {
+ if (!stralloc_copys(sa,name)) return DNS_MEM;
+ return 0;
+ }
+ }
+ return DNS_HARD;
+}
+
+static int dns_ipplus(ia,sa,pref)
+ipalloc *ia;
+stralloc *sa;
+int pref;
+{
+ int r;
+ struct ip_mx ix;
+
+ if (sa->len && (sa->s[0] == '['))
+ {
+ if (!stralloc_copy(&glue,sa)) return DNS_MEM;
+ if (!stralloc_0(&glue)) return DNS_MEM;
+ ix.pref = 0;
+ if (!glue.s[ip_scanbracket(glue.s,&ix.ip)])
+ {
+ if (!ipalloc_append(ia,&ix)) return DNS_MEM;
+ return 0;
+ }
+ }
+
+ switch(resolve(sa,T_A))
+ {
+ case DNS_MEM: return DNS_MEM;
+ case DNS_SOFT: return DNS_SOFT;
+ case DNS_HARD: return DNS_HARD;
+ }
+ while ((r = findip(T_A)) != 2)
+ {
+ ix.ip = ip;
+ ix.pref = pref;
+ if (r == DNS_SOFT) return DNS_SOFT;
+ if (r == 1)
+ if (!ipalloc_append(ia,&ix)) return DNS_MEM;
+ }
+ return 0;
+}
+
+int dns_ip(ia,sa)
+ipalloc *ia;
+stralloc *sa;
+{
+ if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
+ ia->len = 0;
+ return dns_ipplus(ia,sa,0);
+}
+
+int dns_mxip(ia,sa,random)
+ipalloc *ia;
+stralloc *sa;
+unsigned long random;
+{
+ int r;
+ struct mx { stralloc sa; unsigned short p; } *mx;
+ int nummx;
+ int i;
+ int j;
+ int flagsoft;
+
+ if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
+ ia->len = 0;
+
+ if (sa->len && (sa->s[0] == '['))
+ {
+ struct ip_mx ix;
+ if (!stralloc_copy(&glue,sa)) return DNS_MEM;
+ if (!stralloc_0(&glue)) return DNS_MEM;
+ ix.pref = 0;
+ if (!glue.s[ip_scanbracket(glue.s,&ix.ip)])
+ {
+ if (!ipalloc_append(ia,&ix)) return DNS_MEM;
+ return 0;
+ }
+ }
+
+ switch(resolve(sa,T_MX))
+ {
+ case DNS_MEM: return DNS_MEM;
+ case DNS_SOFT: return DNS_SOFT;
+ case DNS_HARD: return dns_ip(ia,sa);
+ }
+
+ mx = (struct mx *) alloc(numanswers * sizeof(struct mx));
+ if (!mx) return DNS_MEM;
+ nummx = 0;
+
+ while ((r = findmx(T_MX)) != 2)
+ {
+ if (r == DNS_SOFT) { alloc_free(mx); return DNS_SOFT; }
+ if (r == 1)
+ {
+ mx[nummx].p = pref;
+ mx[nummx].sa.s = 0;
+ if (!stralloc_copys(&mx[nummx].sa,name))
+ {
+ while (nummx > 0) alloc_free(mx[--nummx].sa.s);
+ alloc_free(mx); return DNS_MEM;
+ }
+ ++nummx;
+ }
+ }
+
+ if (!nummx) return dns_ip(ia,sa); /* e.g., CNAME -> A */
+
+ flagsoft = 0;
+ while (nummx > 0)
+ {
+ unsigned long numsame;
+
+ i = 0;
+ numsame = 1;
+ for (j = 1;j < nummx;++j)
+ if (mx[j].p < mx[i].p)
+ {
+ i = j;
+ numsame = 1;
+ }
+ else if (mx[j].p == mx[i].p)
+ {
+ ++numsame;
+ random = random * 69069 + 1;
+ if ((random / 2) < (2147483647 / numsame))
+ i = j;
+ }
+
+ switch(dns_ipplus(ia,&mx[i].sa,mx[i].p))
+ {
+ case DNS_MEM: case DNS_SOFT:
+ flagsoft = 1; break;
+ }
+
+ alloc_free(mx[i].sa.s);
+ mx[i] = mx[--nummx];
+ }
+
+ alloc_free(mx);
+ return flagsoft;
+}
diff --git a/dns.h b/dns.h
new file mode 100644
index 0000000..bca9490
--- /dev/null
+++ b/dns.h
@@ -0,0 +1,14 @@
+#ifndef DNS_H
+#define DNS_H
+
+#define DNS_SOFT -1
+#define DNS_HARD -2
+#define DNS_MEM -3
+
+void dns_init();
+int dns_cname();
+int dns_mxip();
+int dns_ip();
+int dns_ptr();
+
+#endif
diff --git a/dns.lib.do b/dns.lib.do
new file mode 100644
index 0000000..2c73eab
--- /dev/null
+++ b/dns.lib.do
@@ -0,0 +1,14 @@
+dependon tryrsolv.c compile load socket.lib dns.o \
+ipalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a
+
+( ./compile tryrsolv.c && ./load tryrsolv dns.o \
+ipalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \
+-lresolv `cat socket.lib` ) >/dev/null 2>&1 \
+&& echo -lresolv
+rm -f tryrsolv.o tryrsolv
+
+formake '( ( ./compile tryrsolv.c && ./load tryrsolv dns.o \'
+formake 'ipalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \'
+formake '-lresolv `cat socket.lib` ) >/dev/null 2>&1 \'
+formake '&& echo -lresolv || exit 0 ) > dns.lib'
+formake 'rm -f tryrsolv.o tryrsolv'
diff --git a/env.c b/env.c
new file mode 100644
index 0000000..05d527b
--- /dev/null
+++ b/env.c
@@ -0,0 +1,113 @@
+/* env.c, envread.c, env.h: environ library
+Daniel J. Bernstein, djb@silverton.berkeley.edu.
+Depends on str.h, alloc.h.
+Requires environ.
+19960113: rewrite. warning: interface is different.
+No known patent problems.
+*/
+
+#include "str.h"
+#include "alloc.h"
+#include "env.h"
+
+int env_isinit = 0; /* if env_isinit: */
+static int ea; /* environ is a pointer to ea+1 char*'s. */
+static int en; /* the first en of those are ALLOCATED. environ[en] is 0. */
+
+static void env_goodbye(i) int i;
+{
+ alloc_free(environ[i]);
+ environ[i] = environ[--en];
+ environ[en] = 0;
+}
+
+static char *null = 0;
+
+void env_clear()
+{
+ if (env_isinit) while (en) env_goodbye(0);
+ else environ = &null;
+}
+
+static void env_unsetlen(s,len) char *s; int len;
+{
+ int i;
+ for (i = en - 1;i >= 0;--i)
+ if (!str_diffn(s,environ[i],len))
+ if (environ[i][len] == '=')
+ env_goodbye(i);
+}
+
+int env_unset(s) char *s;
+{
+ if (!env_isinit) if (!env_init()) return 0;
+ env_unsetlen(s,str_len(s));
+ return 1;
+}
+
+static int env_add(s) char *s;
+{
+ char *t;
+ t = env_findeq(s);
+ if (t) env_unsetlen(s,t - s);
+ if (en == ea)
+ {
+ ea += 30;
+ if (!alloc_re(&environ,(en + 1) * sizeof(char *),(ea + 1) * sizeof(char *)))
+ { ea = en; return 0; }
+ }
+ environ[en++] = s;
+ environ[en] = 0;
+ return 1;
+}
+
+int env_put(s) char *s;
+{
+ char *u;
+ if (!env_isinit) if (!env_init()) return 0;
+ u = alloc(str_len(s) + 1);
+ if (!u) return 0;
+ str_copy(u,s);
+ if (!env_add(u)) { alloc_free(u); return 0; }
+ return 1;
+}
+
+int env_put2(s,t) char *s; char *t;
+{
+ char *u;
+ int slen;
+ if (!env_isinit) if (!env_init()) return 0;
+ slen = str_len(s);
+ u = alloc(slen + str_len(t) + 2);
+ if (!u) return 0;
+ str_copy(u,s);
+ u[slen] = '=';
+ str_copy(u + slen + 1,t);
+ if (!env_add(u)) { alloc_free(u); return 0; }
+ return 1;
+}
+
+int env_init()
+{
+ char **newenviron;
+ int i;
+ for (en = 0;environ[en];++en) ;
+ ea = en + 10;
+ newenviron = (char **) alloc((ea + 1) * sizeof(char *));
+ if (!newenviron) return 0;
+ for (en = 0;environ[en];++en)
+ {
+ newenviron[en] = alloc(str_len(environ[en]) + 1);
+ if (!newenviron[en])
+ {
+ for (i = 0;i < en;++i) alloc_free(newenviron[i]);
+ alloc_free(newenviron);
+ return 0;
+ }
+ str_copy(newenviron[en],environ[en]);
+ }
+ newenviron[en] = 0;
+ environ = newenviron;
+ env_isinit = 1;
+ return 1;
+}
diff --git a/env.h b/env.h
new file mode 100644
index 0000000..9befc79
--- /dev/null
+++ b/env.h
@@ -0,0 +1,17 @@
+#ifndef ENV_H
+#define ENV_H
+
+extern int env_isinit;
+
+extern int env_init();
+extern int env_put();
+extern int env_put2();
+extern int env_unset();
+extern /*@null@*/char *env_get();
+extern char *env_pick();
+extern void env_clear();
+extern char *env_findeq();
+
+extern char **environ;
+
+#endif
diff --git a/env=l b/env=l
new file mode 100644
index 0000000..9f9140a
--- /dev/null
+++ b/env=l
@@ -0,0 +1,2 @@
+env.o
+envread.o
diff --git a/envread.c b/envread.c
new file mode 100644
index 0000000..80185de
--- /dev/null
+++ b/envread.c
@@ -0,0 +1,30 @@
+#include "env.h"
+#include "str.h"
+
+extern /*@null@*/char *env_get(s)
+char *s;
+{
+ int i;
+ unsigned int slen;
+ char *envi;
+
+ slen = str_len(s);
+ for (i = 0;envi = environ[i];++i)
+ if ((!str_diffn(s,envi,slen)) && (envi[slen] == '='))
+ return envi + slen + 1;
+ return 0;
+}
+
+extern char *env_pick()
+{
+ return environ[0];
+}
+
+extern char *env_findeq(s)
+char *s;
+{
+ for (;*s;++s)
+ if (*s == '=')
+ return s;
+ return 0;
+}
diff --git a/error.c b/error.c
new file mode 100644
index 0000000..d51304f
--- /dev/null
+++ b/error.c
@@ -0,0 +1,95 @@
+#include <errno.h>
+#include "error.h"
+
+/* warning: as coverage improves here, should update error_{str,temp} */
+
+int error_intr =
+#ifdef EINTR
+EINTR;
+#else
+-1;
+#endif
+
+int error_nomem =
+#ifdef ENOMEM
+ENOMEM;
+#else
+-2;
+#endif
+
+int error_noent =
+#ifdef ENOENT
+ENOENT;
+#else
+-3;
+#endif
+
+int error_txtbsy =
+#ifdef ETXTBSY
+ETXTBSY;
+#else
+-4;
+#endif
+
+int error_io =
+#ifdef EIO
+EIO;
+#else
+-5;
+#endif
+
+int error_exist =
+#ifdef EEXIST
+EEXIST;
+#else
+-6;
+#endif
+
+int error_timeout =
+#ifdef ETIMEDOUT
+ETIMEDOUT;
+#else
+-7;
+#endif
+
+int error_inprogress =
+#ifdef EINPROGRESS
+EINPROGRESS;
+#else
+-8;
+#endif
+
+int error_wouldblock =
+#ifdef EWOULDBLOCK
+EWOULDBLOCK;
+#else
+-9;
+#endif
+
+int error_again =
+#ifdef EAGAIN
+EAGAIN;
+#else
+-10;
+#endif
+
+int error_pipe =
+#ifdef EPIPE
+EPIPE;
+#else
+-11;
+#endif
+
+int error_perm =
+#ifdef EPERM
+EPERM;
+#else
+-12;
+#endif
+
+int error_acces =
+#ifdef EACCES
+EACCES;
+#else
+-13;
+#endif
diff --git a/error.h b/error.h
new file mode 100644
index 0000000..01bd3dc
--- /dev/null
+++ b/error.h
@@ -0,0 +1,23 @@
+#ifndef ERROR_H
+#define ERROR_H
+
+extern int errno;
+
+extern int error_intr;
+extern int error_nomem;
+extern int error_noent;
+extern int error_txtbsy;
+extern int error_io;
+extern int error_exist;
+extern int error_timeout;
+extern int error_inprogress;
+extern int error_wouldblock;
+extern int error_again;
+extern int error_pipe;
+extern int error_perm;
+extern int error_acces;
+
+extern char *error_str();
+extern int error_temp();
+
+#endif
diff --git a/error=l b/error=l
new file mode 100644
index 0000000..2a9cb84
--- /dev/null
+++ b/error=l
@@ -0,0 +1,2 @@
+error.o
+error_str.o
diff --git a/error_str.c b/error_str.c
new file mode 100644
index 0000000..804d1fa
--- /dev/null
+++ b/error_str.c
@@ -0,0 +1,276 @@
+#include <errno.h>
+#include "error.h"
+
+#define X(e,s) if (i == e) return s;
+
+char *error_str(i)
+int i;
+{
+ X(0,"no error")
+ X(error_intr,"interrupted system call")
+ X(error_nomem,"out of memory")
+ X(error_noent,"file does not exist")
+ X(error_txtbsy,"text busy")
+ X(error_io,"input/output error")
+ X(error_exist,"file already exists")
+ X(error_timeout,"timed out")
+ X(error_inprogress,"operation in progress")
+ X(error_again,"temporary failure")
+ X(error_wouldblock,"input/output would block")
+ X(error_pipe,"broken pipe")
+ X(error_perm,"permission denied")
+ X(error_acces,"access denied")
+#ifdef ESRCH
+ X(ESRCH,"no such process")
+#endif
+#ifdef ENXIO
+ X(ENXIO,"device not configured")
+#endif
+#ifdef E2BIG
+ X(E2BIG,"argument list too long")
+#endif
+#ifdef ENOEXEC
+ X(ENOEXEC,"exec format error")
+#endif
+#ifdef EBADF
+ X(EBADF,"file descriptor not open")
+#endif
+#ifdef ECHILD
+ X(ECHILD,"no child processes")
+#endif
+#ifdef EDEADLK
+ X(EDEADLK,"operation would cause deadlock")
+#endif
+#ifdef EFAULT
+ X(EFAULT,"bad address")
+#endif
+#ifdef ENOTBLK
+ X(ENOTBLK,"not a block device")
+#endif
+#ifdef EBUSY
+ X(EBUSY,"device busy")
+#endif
+#ifdef EXDEV
+ X(EXDEV,"cross-device link")
+#endif
+#ifdef ENODEV
+ X(ENODEV,"device does not support operation")
+#endif
+#ifdef ENOTDIR
+ X(ENOTDIR,"not a directory")
+#endif
+#ifdef EISDIR
+ X(EISDIR,"is a directory")
+#endif
+#ifdef EINVAL
+ X(EINVAL,"invalid argument")
+#endif
+#ifdef ENFILE
+ X(ENFILE,"system cannot open more files")
+#endif
+#ifdef EMFILE
+ X(EMFILE,"process cannot open more files")
+#endif
+#ifdef ENOTTY
+ X(ENOTTY,"not a tty")
+#endif
+#ifdef EFBIG
+ X(EFBIG,"file too big")
+#endif
+#ifdef ENOSPC
+ X(ENOSPC,"out of disk space")
+#endif
+#ifdef ESPIPE
+ X(ESPIPE,"unseekable descriptor")
+#endif
+#ifdef EROFS
+ X(EROFS,"read-only file system")
+#endif
+#ifdef EMLINK
+ X(EMLINK,"too many links")
+#endif
+#ifdef EDOM
+ X(EDOM,"input out of range")
+#endif
+#ifdef ERANGE
+ X(ERANGE,"output out of range")
+#endif
+#ifdef EALREADY
+ X(EALREADY,"operation already in progress")
+#endif
+#ifdef ENOTSOCK
+ X(ENOTSOCK,"not a socket")
+#endif
+#ifdef EDESTADDRREQ
+ X(EDESTADDRREQ,"destination address required")
+#endif
+#ifdef EMSGSIZE
+ X(EMSGSIZE,"message too long")
+#endif
+#ifdef EPROTOTYPE
+ X(EPROTOTYPE,"incorrect protocol type")
+#endif
+#ifdef ENOPROTOOPT
+ X(ENOPROTOOPT,"protocol not available")
+#endif
+#ifdef EPROTONOSUPPORT
+ X(EPROTONOSUPPORT,"protocol not supported")
+#endif
+#ifdef ESOCKTNOSUPPORT
+ X(ESOCKTNOSUPPORT,"socket type not supported")
+#endif
+#ifdef EOPNOTSUPP
+ X(EOPNOTSUPP,"operation not supported")
+#endif
+#ifdef EPFNOSUPPORT
+ X(EPFNOSUPPORT,"protocol family not supported")
+#endif
+#ifdef EAFNOSUPPORT
+ X(EAFNOSUPPORT,"address family not supported")
+#endif
+#ifdef EADDRINUSE
+ X(EADDRINUSE,"address already used")
+#endif
+#ifdef EADDRNOTAVAIL
+ X(EADDRNOTAVAIL,"address not available")
+#endif
+#ifdef ENETDOWN
+ X(ENETDOWN,"network down")
+#endif
+#ifdef ENETUNREACH
+ X(ENETUNREACH,"network unreachable")
+#endif
+#ifdef ENETRESET
+ X(ENETRESET,"network reset")
+#endif
+#ifdef ECONNABORTED
+ X(ECONNABORTED,"connection aborted")
+#endif
+#ifdef ECONNRESET
+ X(ECONNRESET,"connection reset")
+#endif
+#ifdef ENOBUFS
+ X(ENOBUFS,"out of buffer space")
+#endif
+#ifdef EISCONN
+ X(EISCONN,"already connected")
+#endif
+#ifdef ENOTCONN
+ X(ENOTCONN,"not connected")
+#endif
+#ifdef ESHUTDOWN
+ X(ESHUTDOWN,"socket shut down")
+#endif
+#ifdef ETOOMANYREFS
+ X(ETOOMANYREFS,"too many references")
+#endif
+#ifdef ECONNREFUSED
+ X(ECONNREFUSED,"connection refused")
+#endif
+#ifdef ELOOP
+ X(ELOOP,"symbolic link loop")
+#endif
+#ifdef ENAMETOOLONG
+ X(ENAMETOOLONG,"file name too long")
+#endif
+#ifdef EHOSTDOWN
+ X(EHOSTDOWN,"host down")
+#endif
+#ifdef EHOSTUNREACH
+ X(EHOSTUNREACH,"host unreachable")
+#endif
+#ifdef ENOTEMPTY
+ X(ENOTEMPTY,"directory not empty")
+#endif
+#ifdef EPROCLIM
+ X(EPROCLIM,"too many processes")
+#endif
+#ifdef EUSERS
+ X(EUSERS,"too many users")
+#endif
+#ifdef EDQUOT
+ X(EDQUOT,"disk quota exceeded")
+#endif
+#ifdef ESTALE
+ X(ESTALE,"stale NFS file handle")
+#endif
+#ifdef EREMOTE
+ X(EREMOTE,"too many levels of remote in path")
+#endif
+#ifdef EBADRPC
+ X(EBADRPC,"RPC structure is bad")
+#endif
+#ifdef ERPCMISMATCH
+ X(ERPCMISMATCH,"RPC version mismatch")
+#endif
+#ifdef EPROGUNAVAIL
+ X(EPROGUNAVAIL,"RPC program unavailable")
+#endif
+#ifdef EPROGMISMATCH
+ X(EPROGMISMATCH,"program version mismatch")
+#endif
+#ifdef EPROCUNAVAIL
+ X(EPROCUNAVAIL,"bad procedure for program")
+#endif
+#ifdef ENOLCK
+ X(ENOLCK,"no locks available")
+#endif
+#ifdef ENOSYS
+ X(ENOSYS,"system call not available")
+#endif
+#ifdef EFTYPE
+ X(EFTYPE,"bad file type")
+#endif
+#ifdef EAUTH
+ X(EAUTH,"authentication error")
+#endif
+#ifdef ENEEDAUTH
+ X(ENEEDAUTH,"not authenticated")
+#endif
+#ifdef ENOSTR
+ X(ENOSTR,"not a stream device")
+#endif
+#ifdef ETIME
+ X(ETIME,"timer expired")
+#endif
+#ifdef ENOSR
+ X(ENOSR,"out of stream resources")
+#endif
+#ifdef ENOMSG
+ X(ENOMSG,"no message of desired type")
+#endif
+#ifdef EBADMSG
+ X(EBADMSG,"bad message type")
+#endif
+#ifdef EIDRM
+ X(EIDRM,"identifier removed")
+#endif
+#ifdef ENONET
+ X(ENONET,"machine not on network")
+#endif
+#ifdef ERREMOTE
+ X(ERREMOTE,"object not local")
+#endif
+#ifdef ENOLINK
+ X(ENOLINK,"link severed")
+#endif
+#ifdef EADV
+ X(EADV,"advertise error")
+#endif
+#ifdef ESRMNT
+ X(ESRMNT,"srmount error")
+#endif
+#ifdef ECOMM
+ X(ECOMM,"communication error")
+#endif
+#ifdef EPROTO
+ X(EPROTO,"protocol error")
+#endif
+#ifdef EMULTIHOP
+ X(EMULTIHOP,"multihop attempted")
+#endif
+#ifdef EREMCHG
+ X(EREMCHG,"remote address changed")
+#endif
+ return "unknown error";
+}
diff --git a/exit.h b/exit.h
new file mode 100644
index 0000000..39011c8
--- /dev/null
+++ b/exit.h
@@ -0,0 +1,6 @@
+#ifndef EXIT_H
+#define EXIT_H
+
+extern void _exit();
+
+#endif
diff --git a/fd.h b/fd.h
new file mode 100644
index 0000000..c3d6e3e
--- /dev/null
+++ b/fd.h
@@ -0,0 +1,7 @@
+#ifndef FD_H
+#define FD_H
+
+extern int fd_copy();
+extern int fd_move();
+
+#endif
diff --git a/fd=l b/fd=l
new file mode 100644
index 0000000..402ffe2
--- /dev/null
+++ b/fd=l
@@ -0,0 +1,2 @@
+fd_copy.o
+fd_move.o
diff --git a/fd_copy.c b/fd_copy.c
new file mode 100644
index 0000000..b9f7167
--- /dev/null
+++ b/fd_copy.c
@@ -0,0 +1,13 @@
+#include <fcntl.h>
+#include "fd.h"
+
+int fd_copy(to,from)
+int to;
+int from;
+{
+ if (to == from) return 0;
+ if (fcntl(from,F_GETFL,0) == -1) return -1;
+ close(to);
+ if (fcntl(from,F_DUPFD,to) == -1) return -1;
+ return 0;
+}
diff --git a/fd_move.c b/fd_move.c
new file mode 100644
index 0000000..1aa557f
--- /dev/null
+++ b/fd_move.c
@@ -0,0 +1,11 @@
+#include "fd.h"
+
+int fd_move(to,from)
+int to;
+int from;
+{
+ if (to == from) return 0;
+ if (fd_copy(to,from) == -1) return -1;
+ close(from);
+ return 0;
+}
diff --git a/find-systype.sh b/find-systype.sh
new file mode 100644
index 0000000..16266d3
--- /dev/null
+++ b/find-systype.sh
@@ -0,0 +1,144 @@
+# oper-:arch-:syst-:chip-:kern-
+# oper = operating system type; e.g., sunos-4.1.4
+# arch = machine language; e.g., sparc
+# syst = which binaries can run; e.g., sun4
+# chip = chip model; e.g., micro-2-80
+# kern = kernel version; e.g., sun4m
+# dependence: arch --- chip
+# \ \
+# oper --- syst --- kern
+# so, for example, syst is interpreted in light of oper, but chip is not.
+# anyway, no slashes, no extra colons, no uppercase letters.
+# the point of the extra -'s is to ease parsing: can add hierarchies later.
+# e.g., *:i386-*:*:pentium-*:* would handle pentium-100 as well as pentium,
+# and i386-486 (486s do have more instructions, you know) as well as i386.
+# the idea here is to include ALL useful available information.
+
+exec 2>/dev/null
+sys="`uname -s | tr '/:[A-Z]' '..[a-z]'`"
+if [ x"$sys" != x ]
+then
+ unamer="`uname -r | tr /: ..`"
+ unamem="`uname -m | tr /: ..`"
+ unamev="`uname -v | tr /: ..`"
+
+ case "$sys" in
+ bsd.os)
+ # in bsd 4.4, uname -v does not have useful info.
+ # in bsd 4.4, uname -m is arch, not chip.
+ oper="$sys-$unamer"
+ arch="$unamem"
+ syst=""
+ chip="`sysctl -n hw.model`"
+ kern=""
+ ;;
+ freebsd)
+ # see above about bsd 4.4
+ oper="$sys-$unamer"
+ arch="$unamem"
+ syst=""
+ chip="`sysctl -n hw.model`" # hopefully
+ kern=""
+ ;;
+ netbsd)
+ # see above about bsd 4.4
+ oper="$sys-$unamer"
+ arch="$unamem"
+ syst=""
+ chip="`sysctl -n hw.model`" # hopefully
+ kern=""
+ ;;
+ linux)
+ # as in bsd 4.4, uname -v does not have useful info.
+ oper="$sys-$unamer"
+ syst=""
+ chip="$unamem"
+ kern=""
+ case "$chip" in
+ i386|i486|i586|i686)
+ arch="i386"
+ ;;
+ alpha)
+ arch="alpha"
+ ;;
+ esac
+ ;;
+ aix)
+ # naturally IBM has to get uname -r and uname -v backwards. dorks.
+ oper="$sys-$unamev-$unamer"
+ arch="`arch | tr /: ..`"
+ syst=""
+ chip="$unamem"
+ kern=""
+ ;;
+ sunos)
+ oper="$sys-$unamer-$unamev"
+ arch="`(uname -p || mach) | tr /: ..`"
+ syst="`arch | tr /: ..`"
+ chip="$unamem" # this is wrong; is there any way to get the real info?
+ kern="`arch -k | tr /: ..`"
+ ;;
+ unix_sv)
+ oper="$sys-$unamer-$unamev"
+ arch="`uname -m`"
+ syst=""
+ chip="$unamem"
+ kern=""
+ ;;
+ *)
+ oper="$sys-$unamer-$unamev"
+ arch="`arch | tr /: ..`"
+ syst=""
+ chip="$unamem"
+ kern=""
+ ;;
+ esac
+else
+ $CC -c trycpp.c
+ $LD -o trycpp trycpp.o
+ case `./trycpp` in
+ nextstep)
+ oper="nextstep-`hostinfo | sed -n 's/^[ ]*NeXT Mach \([^:]*\):.*$/\1/p'`"
+ arch="`hostinfo | sed -n 's/^Processor type: \(.*\) (.*)$/\1/p' | tr /: ..`"
+ syst=""
+ chip="`hostinfo | sed -n 's/^Processor type: .* (\(.*\))$/\1/p' | tr ' /:' '...'`"
+ kern=""
+ ;;
+ *)
+ oper="unknown"
+ arch=""
+ syst=""
+ chip=""
+ kern=""
+ ;;
+ esac
+ rm -f trycpp.o trycpp
+fi
+
+case "$chip" in
+80486)
+ # let's try to be consistent here. (BSD/OS)
+ chip=i486
+ ;;
+i486DX)
+ # respect the hyphen hierarchy. (FreeBSD)
+ chip=i486-dx
+ ;;
+i486.DX2)
+ # respect the hyphen hierarchy. (FreeBSD)
+ chip=i486-dx2
+ ;;
+Intel.586)
+ # no, you nitwits, there is no such chip. (NeXTStep)
+ chip=pentium
+ ;;
+i586)
+ # no, you nitwits, there is no such chip. (Linux)
+ chip=pentium
+ ;;
+i686)
+ # STOP SAYING THAT! (Linux)
+ chip=ppro
+esac
+
+echo "$oper-:$arch-:$syst-:$chip-:$kern-" | tr ' [A-Z]' '.[a-z]'
diff --git a/finger@.sh b/finger@.sh
new file mode 100644
index 0000000..54f8a8c
--- /dev/null
+++ b/finger@.sh
@@ -0,0 +1,4 @@
+echo "${2-}" | BIN/tcpclient -RHl0 -- "${1-0}" 79 sh -c '
+ BIN/addcr >&7
+ exec BIN/delcr <&6
+' | cat -v
diff --git a/finger@=s b/finger@=s
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/finger@=s
diff --git a/fmt.h b/fmt.h
new file mode 100644
index 0000000..ba2fe16
--- /dev/null
+++ b/fmt.h
@@ -0,0 +1,25 @@
+#ifndef FMT_H
+#define FMT_H
+
+#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
+#define FMT_LEN ((char *) 0) /* convenient abbreviation */
+
+extern unsigned int fmt_uint();
+extern unsigned int fmt_uint0();
+extern unsigned int fmt_xint();
+extern unsigned int fmt_nbbint();
+extern unsigned int fmt_ushort();
+extern unsigned int fmt_xshort();
+extern unsigned int fmt_nbbshort();
+extern unsigned int fmt_ulong();
+extern unsigned int fmt_xlong();
+extern unsigned int fmt_nbblong();
+
+extern unsigned int fmt_plusminus();
+extern unsigned int fmt_minus();
+extern unsigned int fmt_0x();
+
+extern unsigned int fmt_str();
+extern unsigned int fmt_strn();
+
+#endif
diff --git a/fmt_str.c b/fmt_str.c
new file mode 100644
index 0000000..48930cf
--- /dev/null
+++ b/fmt_str.c
@@ -0,0 +1,12 @@
+#include "fmt.h"
+
+unsigned int fmt_str(s,t)
+register char *s; register char *t;
+{
+ register unsigned int len;
+ char ch;
+ len = 0;
+ if (s) { while (ch = t[len]) s[len++] = ch; }
+ else while (t[len]) len++;
+ return len;
+}
diff --git a/fmt_ulong.c b/fmt_ulong.c
new file mode 100644
index 0000000..ab12e8c
--- /dev/null
+++ b/fmt_ulong.c
@@ -0,0 +1,13 @@
+#include "fmt.h"
+
+unsigned int fmt_ulong(s,u) register char *s; register unsigned long u;
+{
+ register unsigned int len; register unsigned long q;
+ len = 1; q = u;
+ while (q > 9) { ++len; q /= 10; }
+ if (s) {
+ s += len;
+ do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */
+ }
+ return len;
+}
diff --git a/fs=l b/fs=l
new file mode 100644
index 0000000..a2a5dd1
--- /dev/null
+++ b/fs=l
@@ -0,0 +1,4 @@
+fmt_str.o
+fmt_ulong.o
+scan_ulong.o
+scan_8long.o
diff --git a/gen_alloc.h b/gen_alloc.h
new file mode 100644
index 0000000..b94a956
--- /dev/null
+++ b/gen_alloc.h
@@ -0,0 +1,7 @@
+#ifndef GEN_ALLOC_H
+#define GEN_ALLOC_H
+
+#define GEN_ALLOC_typedef(ta,type,field,len,a) \
+ typedef struct ta { type *field; unsigned int len; unsigned int a; } ta;
+
+#endif
diff --git a/gen_allocdefs.h b/gen_allocdefs.h
new file mode 100644
index 0000000..783a9b1
--- /dev/null
+++ b/gen_allocdefs.h
@@ -0,0 +1,34 @@
+#ifndef GEN_ALLOC_DEFS_H
+#define GEN_ALLOC_DEFS_H
+
+#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \
+int ta_ready(x,n) register ta *x; register unsigned int n; \
+{ register unsigned int i; \
+ if (x->field) { \
+ i = x->a; \
+ if (n > i) { \
+ x->a = base + n + (n >> 3); \
+ if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \
+ x->a = i; return 0; } \
+ return 1; } \
+ x->len = 0; \
+ return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); }
+
+#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \
+int ta_rplus(x,n) register ta *x; register unsigned int n; \
+{ register unsigned int i; \
+ if (x->field) { \
+ i = x->a; n += x->len; \
+ if (n > i) { \
+ x->a = base + n + (n >> 3); \
+ if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \
+ x->a = i; return 0; } \
+ return 1; } \
+ x->len = 0; \
+ return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); }
+
+#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \
+int ta_append(x,i) register ta *x; register type *i; \
+{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; }
+
+#endif
diff --git a/getln.c b/getln.c
new file mode 100644
index 0000000..c5cb097
--- /dev/null
+++ b/getln.c
@@ -0,0 +1,20 @@
+#include "substdio.h"
+#include "byte.h"
+#include "stralloc.h"
+#include "getln.h"
+
+int getln(ss,sa,match,sep)
+register substdio *ss;
+register stralloc *sa;
+int *match;
+int sep;
+{
+ char *cont;
+ unsigned int clen;
+
+ if (getln2(ss,sa,&cont,&clen,sep) == -1) return -1;
+ if (!clen) { *match = 0; return 0; }
+ if (!stralloc_catb(sa,cont,clen)) return -1;
+ *match = 1;
+ return 0;
+}
diff --git a/getln.h b/getln.h
new file mode 100644
index 0000000..cf4f934
--- /dev/null
+++ b/getln.h
@@ -0,0 +1,7 @@
+#ifndef GETLN_H
+#define GETLN_H
+
+extern int getln();
+extern int getln2();
+
+#endif
diff --git a/getln2.c b/getln2.c
new file mode 100644
index 0000000..9e576e9
--- /dev/null
+++ b/getln2.c
@@ -0,0 +1,31 @@
+#include "substdio.h"
+#include "stralloc.h"
+#include "byte.h"
+#include "getln.h"
+
+int getln2(ss,sa,cont,clen,sep)
+register substdio *ss;
+register stralloc *sa;
+/*@out@*/char **cont;
+/*@out@*/unsigned int *clen;
+int sep;
+{
+ register char *x;
+ register unsigned int i;
+ int n;
+
+ if (!stralloc_ready(sa,0)) return -1;
+ sa->len = 0;
+
+ for (;;) {
+ n = substdio_feed(ss);
+ if (n < 0) return -1;
+ if (n == 0) { *clen = 0; return 0; }
+ x = substdio_PEEK(ss);
+ i = byte_chr(x,n,sep);
+ if (i < n) { substdio_SEEK(ss,*clen = i + 1); *cont = x; return 0; }
+ if (!stralloc_readyplus(sa,n)) return -1;
+ i = sa->len;
+ sa->len = i + substdio_get(ss,sa->s + i,n);
+ }
+}
diff --git a/getln=l b/getln=l
new file mode 100644
index 0000000..b0f37fa
--- /dev/null
+++ b/getln=l
@@ -0,0 +1,2 @@
+getln.o
+getln2.o
diff --git a/getopt=l b/getopt=l
new file mode 100644
index 0000000..a667e1e
--- /dev/null
+++ b/getopt=l
@@ -0,0 +1,2 @@
+subgetopt.o
+sgetopt.o
diff --git a/hassgact.h.do b/hassgact.h.do
new file mode 100644
index 0000000..df277d5
--- /dev/null
+++ b/hassgact.h.do
@@ -0,0 +1,7 @@
+dependon trysgact.c compile load
+( ./compile trysgact.c && ./load trysgact ) >/dev/null 2>&1 \
+&& echo \#define HASSIGACTION 1
+rm -f trysgact.o trysgact
+formake '( ( ./compile trysgact.c && ./load trysgact ) >/dev/null 2>&1 \'
+formake '&& echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h'
+formake 'rm -f trysgact.o trysgact'
diff --git a/hassgprm.h.do b/hassgprm.h.do
new file mode 100644
index 0000000..6ae8f47
--- /dev/null
+++ b/hassgprm.h.do
@@ -0,0 +1,7 @@
+dependon trysgprm.c compile load
+( ./compile trysgprm.c && ./load trysgprm ) >/dev/null 2>&1 \
+&& echo \#define HASSIGPROCMASK 1
+rm -f trysgprm.o trysgprm
+formake '( ( ./compile trysgprm.c && ./load trysgprm ) >/dev/null 2>&1 \'
+formake '&& echo \#define HASSIGPROCMASK 1 || exit 0 ) > hassgprm.h'
+formake 'rm -f trysgprm.o trysgprm'
diff --git a/haswaitp.h.do b/haswaitp.h.do
new file mode 100644
index 0000000..3cc09f5
--- /dev/null
+++ b/haswaitp.h.do
@@ -0,0 +1,7 @@
+dependon trywaitp.c compile load
+( ./compile trywaitp.c && ./load trywaitp ) >/dev/null 2>&1 \
+&& echo \#define HASWAITPID 1
+rm -f trywaitp.o trywaitp
+formake '( ( ./compile trywaitp.c && ./load trywaitp ) >/dev/null 2>&1 \'
+formake '&& echo \#define HASWAITPID 1 || exit 0 ) > haswaitp.h'
+formake 'rm -f trywaitp.o trywaitp'
diff --git a/install.c b/install.c
new file mode 100644
index 0000000..24f0916
--- /dev/null
+++ b/install.c
@@ -0,0 +1,140 @@
+#include "substdio.h"
+#include "stralloc.h"
+#include "getln.h"
+#include "readwrite.h"
+#include "exit.h"
+#include "open.h"
+#include "error.h"
+#include "strerr.h"
+#include "byte.h"
+
+stralloc target = {0};
+char *to;
+
+#define FATAL "install: fatal: "
+void nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+
+char inbuf[SUBSTDIO_INSIZE];
+char outbuf[SUBSTDIO_OUTSIZE];
+substdio ssin;
+substdio ssout;
+
+void doit(line)
+stralloc *line;
+{
+ char *x;
+ unsigned int xlen;
+ unsigned int i;
+ char *type;
+ char *uidstr;
+ char *gidstr;
+ char *modestr;
+ char *mid;
+ char *name;
+ unsigned long uid;
+ unsigned long gid;
+ unsigned long mode;
+ int fdin;
+ int fdout;
+
+ x = line->s; xlen = line->len;
+
+ type = x;
+ i = byte_chr(x,xlen,':'); if (i == xlen) return;
+ x[i++] = 0; x += i; xlen -= i;
+
+ uidstr = x;
+ i = byte_chr(x,xlen,':'); if (i == xlen) return;
+ x[i++] = 0; x += i; xlen -= i;
+
+ gidstr = x;
+ i = byte_chr(x,xlen,':'); if (i == xlen) return;
+ x[i++] = 0; x += i; xlen -= i;
+
+ modestr = x;
+ i = byte_chr(x,xlen,':'); if (i == xlen) return;
+ x[i++] = 0; x += i; xlen -= i;
+
+ mid = x;
+ i = byte_chr(x,xlen,':'); if (i == xlen) return;
+ x[i++] = 0; x += i; xlen -= i;
+
+ name = x;
+ i = byte_chr(x,xlen,':'); if (i == xlen) return;
+ x[i++] = 0; x += i; xlen -= i;
+
+ if (!stralloc_copys(&target,to)) nomem();
+ if (!stralloc_cats(&target,mid)) nomem();
+ if (!stralloc_cats(&target,name)) nomem();
+ if (!stralloc_0(&target)) nomem();
+
+ uid = -1; if (*uidstr) scan_ulong(uidstr,&uid);
+ gid = -1; if (*gidstr) scan_ulong(gidstr,&gid);
+ scan_8long(modestr,&mode);
+
+ switch(*type) {
+ case 'd':
+ if (mkdir(target.s,0700) == -1)
+ if (errno != error_exist)
+ strerr_die4sys(111,FATAL,"unable to mkdir ",target.s,": ");
+ break;
+
+ case 'c':
+ fdin = open_read(name);
+ if (fdin == -1)
+ strerr_die4sys(111,FATAL,"unable to read ",name,": ");
+ substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf));
+
+ fdout = open_trunc(target.s);
+ if (fdout == -1)
+ strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
+ substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf));
+
+ switch(substdio_copy(&ssout,&ssin)) {
+ case -2:
+ strerr_die4sys(111,FATAL,"unable to read ",name,": ");
+ case -3:
+ strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
+ }
+
+ close(fdin);
+ if (substdio_flush(&ssout) == -1)
+ strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
+ if (fsync(fdout) == -1)
+ strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
+ close(fdout);
+ break;
+
+ default:
+ return;
+ }
+
+ if (chown(target.s,uid,gid) == -1)
+ strerr_die4sys(111,FATAL,"unable to chown ",target.s,": ");
+ if (chmod(target.s,mode) == -1)
+ strerr_die4sys(111,FATAL,"unable to chmod ",target.s,": ");
+}
+
+char buf[256];
+substdio in = SUBSTDIO_FDBUF(read,0,buf,sizeof(buf));
+stralloc line = {0};
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+ int match;
+
+ umask(077);
+
+ to = argv[1];
+ if (!to) strerr_die2x(100,FATAL,"install: usage: install dir");
+
+ for (;;) {
+ if (getln(&in,&line,&match,'\n') == -1)
+ strerr_die2sys(111,FATAL,"unable to read input: ");
+ doit(&line);
+ if (!match)
+ _exit(0);
+ }
+}
diff --git a/install=x b/install=x
new file mode 100644
index 0000000..6dc960b
--- /dev/null
+++ b/install=x
@@ -0,0 +1,9 @@
+getln.a
+strerr.a
+substdio.a
+stralloc.a
+alloc.a
+open.a
+error.a
+str.a
+fs.a
diff --git a/ip.c b/ip.c
new file mode 100644
index 0000000..5528ad5
--- /dev/null
+++ b/ip.c
@@ -0,0 +1,53 @@
+#include "fmt.h"
+#include "scan.h"
+#include "ip.h"
+
+unsigned int ip_fmt(s,ip)
+char *s;
+struct ip_address *ip;
+{
+ unsigned int len;
+ unsigned int i;
+
+ len = 0;
+ i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i;
+ i = fmt_str(s,"."); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i;
+ i = fmt_str(s,"."); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i;
+ i = fmt_str(s,"."); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i;
+ return len;
+}
+
+unsigned int ip_scan(s,ip)
+char *s;
+struct ip_address *ip;
+{
+ unsigned int i;
+ unsigned int len;
+ unsigned long u;
+
+ len = 0;
+ i = scan_ulong(s,&u); if (!i) return 0; ip->d[0] = u; s += i; len += i;
+ if (*s != '.') return 0; ++s; ++len;
+ i = scan_ulong(s,&u); if (!i) return 0; ip->d[1] = u; s += i; len += i;
+ if (*s != '.') return 0; ++s; ++len;
+ i = scan_ulong(s,&u); if (!i) return 0; ip->d[2] = u; s += i; len += i;
+ if (*s != '.') return 0; ++s; ++len;
+ i = scan_ulong(s,&u); if (!i) return 0; ip->d[3] = u; s += i; len += i;
+ return len;
+}
+
+unsigned int ip_scanbracket(s,ip)
+char *s;
+struct ip_address *ip;
+{
+ unsigned int len;
+
+ if (*s != '[') return 0;
+ len = ip_scan(s + 1,ip);
+ if (!len) return 0;
+ if (s[len + 1] != ']') return 0;
+ return len + 2;
+}
diff --git a/ip.h b/ip.h
new file mode 100644
index 0000000..b99002f
--- /dev/null
+++ b/ip.h
@@ -0,0 +1,11 @@
+#ifndef IP_H
+#define IP_H
+
+struct ip_address { unsigned char d[4]; } ;
+
+extern unsigned int ip_fmt();
+#define IPFMT 19
+extern unsigned int ip_scan();
+extern unsigned int ip_scanbracket();
+
+#endif
diff --git a/ipalloc.c b/ipalloc.c
new file mode 100644
index 0000000..81792d5
--- /dev/null
+++ b/ipalloc.c
@@ -0,0 +1,7 @@
+#include "alloc.h"
+#include "gen_allocdefs.h"
+#include "ip.h"
+#include "ipalloc.h"
+
+GEN_ALLOC_readyplus(ipalloc,struct ip_mx,ix,len,a,i,n,x,10,ipalloc_readyplus)
+GEN_ALLOC_append(ipalloc,struct ip_mx,ix,len,a,i,n,x,10,ipalloc_readyplus,ipalloc_append)
diff --git a/ipalloc.h b/ipalloc.h
new file mode 100644
index 0000000..ad61475
--- /dev/null
+++ b/ipalloc.h
@@ -0,0 +1,14 @@
+#ifndef IPALLOC_H
+#define IPALLOC_H
+
+#include "ip.h"
+
+struct ip_mx { struct ip_address ip; int pref; } ;
+
+#include "gen_alloc.h"
+
+GEN_ALLOC_typedef(ipalloc,struct ip_mx,ix,len,a)
+extern int ipalloc_readyplus();
+extern int ipalloc_append();
+
+#endif
diff --git a/it.do b/it.do
new file mode 100644
index 0000000..75437ef
--- /dev/null
+++ b/it.do
@@ -0,0 +1,5 @@
+dependon \
+tcpclient tcpserver tcprules \
+who@ date@ finger@ \
+tcpcat mconnect \
+addcr delcr
diff --git a/make-compile.sh b/make-compile.sh
new file mode 100644
index 0000000..a1eb501
--- /dev/null
+++ b/make-compile.sh
@@ -0,0 +1 @@
+echo exec "$CC" -c '${1+"$@"}'
diff --git a/make-load.sh b/make-load.sh
new file mode 100644
index 0000000..de07d2e
--- /dev/null
+++ b/make-load.sh
@@ -0,0 +1,2 @@
+echo 'main="$1"; shift'
+echo exec "$LD" '-o "$main" "$main".o ${1+"$@"}'
diff --git a/make-makelib.sh b/make-makelib.sh
new file mode 100644
index 0000000..d6b7c8c
--- /dev/null
+++ b/make-makelib.sh
@@ -0,0 +1,16 @@
+echo 'main="$1"; shift'
+echo 'rm -f "$main"'
+echo 'ar cr "$main" ${1+"$@"}'
+
+case "$1" in
+sunos-5.*) ;;
+unix_sv*) ;;
+irix64-*) ;;
+irix-*) ;;
+dgux-*) ;;
+hp-ux-*) ;;
+sco*) ;;
+*)
+ echo 'ranlib "$main"'
+ ;;
+esac
diff --git a/man.do b/man.do
new file mode 100644
index 0000000..4bf14bb
--- /dev/null
+++ b/man.do
@@ -0,0 +1,5 @@
+dependon \
+tcpclient.0 \
+tcpserver.0 \
+tcprules.0 \
+tcp-environ.0
diff --git a/mconnect.sh b/mconnect.sh
new file mode 100644
index 0000000..3d137dd
--- /dev/null
+++ b/mconnect.sh
@@ -0,0 +1,7 @@
+#
+# requires multitee
+#
+BIN/tcpclient -RHl0 -- "${1-0}" "${2-25}" sh -c '
+ exec 4>&1
+ multitee 0:1 6:4e0 | BIN/addcr >&7
+' | BIN/delcr
diff --git a/mconnect=s b/mconnect=s
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mconnect=s
diff --git a/ndelay.c b/ndelay.c
new file mode 100644
index 0000000..438d1d8
--- /dev/null
+++ b/ndelay.c
@@ -0,0 +1,13 @@
+#include <sys/types.h>
+#include <fcntl.h>
+#include "ndelay.h"
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+int ndelay_on(fd)
+int fd;
+{
+ return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK);
+}
diff --git a/ndelay.h b/ndelay.h
new file mode 100644
index 0000000..68c6bce
--- /dev/null
+++ b/ndelay.h
@@ -0,0 +1,7 @@
+#ifndef NDELAY_H
+#define NDELAY_H
+
+extern int ndelay_on();
+extern int ndelay_off();
+
+#endif
diff --git a/ndelay=l b/ndelay=l
new file mode 100644
index 0000000..322dd65
--- /dev/null
+++ b/ndelay=l
@@ -0,0 +1,2 @@
+ndelay.o
+ndelay_off.o
diff --git a/ndelay_off.c b/ndelay_off.c
new file mode 100644
index 0000000..86f8fbf
--- /dev/null
+++ b/ndelay_off.c
@@ -0,0 +1,13 @@
+#include <sys/types.h>
+#include <fcntl.h>
+#include "ndelay.h"
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+int ndelay_off(fd)
+int fd;
+{
+ return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK);
+}
diff --git a/open.h b/open.h
new file mode 100644
index 0000000..c903113
--- /dev/null
+++ b/open.h
@@ -0,0 +1,10 @@
+#ifndef OPEN_H
+#define OPEN_H
+
+extern int open_read();
+extern int open_excl();
+extern int open_append();
+extern int open_trunc();
+extern int open_write();
+
+#endif
diff --git a/open=l b/open=l
new file mode 100644
index 0000000..989ab53
--- /dev/null
+++ b/open=l
@@ -0,0 +1,2 @@
+open_read.o
+open_trunc.o
diff --git a/open_read.c b/open_read.c
new file mode 100644
index 0000000..f503e48
--- /dev/null
+++ b/open_read.c
@@ -0,0 +1,6 @@
+#include <sys/types.h>
+#include <fcntl.h>
+#include "open.h"
+
+int open_read(fn) char *fn;
+{ return open(fn,O_RDONLY | O_NDELAY); }
diff --git a/open_trunc.c b/open_trunc.c
new file mode 100644
index 0000000..e275085
--- /dev/null
+++ b/open_trunc.c
@@ -0,0 +1,6 @@
+#include <sys/types.h>
+#include <fcntl.h>
+#include "open.h"
+
+int open_trunc(fn) char *fn;
+{ return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); }
diff --git a/readwrite.h b/readwrite.h
new file mode 100644
index 0000000..2a64968
--- /dev/null
+++ b/readwrite.h
@@ -0,0 +1,7 @@
+#ifndef READWRITE_H
+#define READWRITE_H
+
+extern int read();
+extern int write();
+
+#endif
diff --git a/remoteinfo.c b/remoteinfo.c
new file mode 100644
index 0000000..c7abd70
--- /dev/null
+++ b/remoteinfo.c
@@ -0,0 +1,77 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include "byte.h"
+#include "substdio.h"
+#include "ip.h"
+#include "fmt.h"
+#include "timeoutconn.h"
+#include "timeoutread.h"
+#include "timeoutwrite.h"
+#include "remoteinfo.h"
+
+static char line[999];
+static int t;
+
+static int mywrite(fd,buf,len) int fd; char *buf; int len;
+{
+ return timeoutwrite(t,fd,buf,len);
+}
+static int myread(fd,buf,len) int fd; char *buf; int len;
+{
+ return timeoutread(t,fd,buf,len);
+}
+
+char *remoteinfo_get(ipr,rp,ipl,lp,timeout)
+struct ip_address *ipr;
+unsigned long rp;
+struct ip_address *ipl;
+unsigned long lp;
+int timeout;
+{
+ char *x;
+ int s;
+ struct sockaddr_in sin;
+ substdio ss;
+ char buf[32];
+ unsigned int len;
+ int numcolons;
+ char ch;
+
+ t = timeout;
+
+ s = socket(AF_INET,SOCK_STREAM,0);
+ if (s == -1) return 0;
+
+ byte_zero(&sin,sizeof(sin));
+ sin.sin_family = AF_INET;
+ byte_copy(&sin.sin_addr,4,ipl);
+ sin.sin_port = 0;
+ if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; }
+ if (timeoutconn(s,ipr,113,timeout) == -1) { close(s); return 0; }
+ fcntl(s,F_SETFL,fcntl(s,F_GETFL,0) & ~O_NDELAY);
+
+ len = 0;
+ len += fmt_ulong(line + len,rp);
+ len += fmt_str(line + len," , ");
+ len += fmt_ulong(line + len,lp);
+ len += fmt_str(line + len,"\r\n");
+
+ substdio_fdbuf(&ss,mywrite,s,buf,sizeof buf);
+ if (substdio_putflush(&ss,line,len) == -1) { close(s); return 0; }
+
+ substdio_fdbuf(&ss,myread,s,buf,sizeof buf);
+ x = line;
+ numcolons = 0;
+ for (;;) {
+ if (substdio_get(&ss,&ch,1) != 1) { close(s); return 0; }
+ if ((ch == ' ') || (ch == '\t') || (ch == '\r')) continue;
+ if (ch == '\n') break;
+ if (numcolons < 3) { if (ch == ':') ++numcolons; }
+ else { *x++ = ch; if (x == line + sizeof(line) - 1) break; }
+ }
+ *x = 0;
+ close(s);
+ return line;
+}
diff --git a/remoteinfo.h b/remoteinfo.h
new file mode 100644
index 0000000..d5d9097
--- /dev/null
+++ b/remoteinfo.h
@@ -0,0 +1,6 @@
+#ifndef REMOTEINFO_H
+#define REMOTEINFO_H
+
+extern char *remoteinfo_get();
+
+#endif
diff --git a/scan.h b/scan.h
new file mode 100644
index 0000000..53ce703
--- /dev/null
+++ b/scan.h
@@ -0,0 +1,27 @@
+#ifndef SCAN_H
+#define SCAN_H
+
+extern unsigned int scan_uint();
+extern unsigned int scan_xint();
+extern unsigned int scan_nbbint();
+extern unsigned int scan_ushort();
+extern unsigned int scan_xshort();
+extern unsigned int scan_nbbshort();
+extern unsigned int scan_ulong();
+extern unsigned int scan_xlong();
+extern unsigned int scan_nbblong();
+
+extern unsigned int scan_plusminus();
+extern unsigned int scan_0x();
+
+extern unsigned int scan_whitenskip();
+extern unsigned int scan_nonwhitenskip();
+extern unsigned int scan_charsetnskip();
+extern unsigned int scan_noncharsetnskip();
+
+extern unsigned int scan_strncmp();
+extern unsigned int scan_memcmp();
+
+extern unsigned int scan_long();
+
+#endif
diff --git a/scan_8long.c b/scan_8long.c
new file mode 100644
index 0000000..8b3a6df
--- /dev/null
+++ b/scan_8long.c
@@ -0,0 +1,11 @@
+#include "scan.h"
+
+unsigned int scan_8long(s,u) register char *s; register unsigned long *u;
+{
+ register unsigned int pos; register unsigned long result;
+ register unsigned long c;
+ pos = 0; result = 0;
+ while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 8)
+ { result = result * 8 + c; ++pos; }
+ *u = result; return pos;
+}
diff --git a/scan_ulong.c b/scan_ulong.c
new file mode 100644
index 0000000..27c41ea
--- /dev/null
+++ b/scan_ulong.c
@@ -0,0 +1,11 @@
+#include "scan.h"
+
+unsigned int scan_ulong(s,u) register char *s; register unsigned long *u;
+{
+ register unsigned int pos; register unsigned long result;
+ register unsigned long c;
+ pos = 0; result = 0;
+ while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10)
+ { result = result * 10 + c; ++pos; }
+ *u = result; return pos;
+}
diff --git a/seek.h b/seek.h
new file mode 100644
index 0000000..964fba3
--- /dev/null
+++ b/seek.h
@@ -0,0 +1,15 @@
+#ifndef SEEK_H
+#define SEEK_H
+
+typedef unsigned long seek_pos;
+
+extern seek_pos seek_cur();
+
+extern int seek_set();
+extern int seek_end();
+
+extern int seek_trunc();
+
+#define seek_begin(fd) (seek_set((fd),(seek_pos) 0))
+
+#endif
diff --git a/seek=l b/seek=l
new file mode 100644
index 0000000..d21b6a1
--- /dev/null
+++ b/seek=l
@@ -0,0 +1,4 @@
+seek_cur.o
+seek_end.o
+seek_set.o
+seek_trunc.o
diff --git a/seek_cur.c b/seek_cur.c
new file mode 100644
index 0000000..c8a3ee8
--- /dev/null
+++ b/seek_cur.c
@@ -0,0 +1,7 @@
+#include <sys/types.h>
+#include "seek.h"
+
+#define CUR 1 /* sigh */
+
+seek_pos seek_cur(fd) int fd;
+{ return lseek(fd,(off_t) 0,CUR); }
diff --git a/seek_end.c b/seek_end.c
new file mode 100644
index 0000000..8a7b3c5
--- /dev/null
+++ b/seek_end.c
@@ -0,0 +1,7 @@
+#include <sys/types.h>
+#include "seek.h"
+
+#define END 2 /* sigh */
+
+int seek_end(fd) int fd;
+{ if (lseek(fd,(off_t) 0,END) == -1) return -1; return 0; }
diff --git a/seek_set.c b/seek_set.c
new file mode 100644
index 0000000..f540664
--- /dev/null
+++ b/seek_set.c
@@ -0,0 +1,7 @@
+#include <sys/types.h>
+#include "seek.h"
+
+#define SET 0 /* sigh */
+
+int seek_set(fd,pos) int fd; seek_pos pos;
+{ if (lseek(fd,(off_t) pos,SET) == -1) return -1; return 0; }
diff --git a/seek_trunc.c b/seek_trunc.c
new file mode 100644
index 0000000..6a1a73e
--- /dev/null
+++ b/seek_trunc.c
@@ -0,0 +1,5 @@
+#include <sys/types.h>
+#include "seek.h"
+
+int seek_trunc(fd,pos) int fd; seek_pos pos;
+{ return ftruncate(fd,(off_t) pos); }
diff --git a/select.h.do b/select.h.do
new file mode 100644
index 0000000..5ab38df
--- /dev/null
+++ b/select.h.do
@@ -0,0 +1,6 @@
+dependon compile trysysel.c select.h1 select.h2
+./compile trysysel.c >/dev/null 2>&1 && cat select.h2 || cat select.h1
+rm -f trysysel.o
+formake '( ./compile trysysel.c >/dev/null 2>&1 \'
+formake '&& cat select.h2 || cat select.h1 ) > select.h'
+formake 'rm -f trysysel.o trysysel'
diff --git a/select.h1 b/select.h1
new file mode 100644
index 0000000..32d0968
--- /dev/null
+++ b/select.h1
@@ -0,0 +1,8 @@
+#ifndef SELECT_H
+#define SELECT_H
+
+#include <sys/types.h>
+#include <sys/time.h>
+extern int select();
+
+#endif
diff --git a/select.h2 b/select.h2
new file mode 100644
index 0000000..eb4b8fe
--- /dev/null
+++ b/select.h2
@@ -0,0 +1,9 @@
+#ifndef SELECT_H
+#define SELECT_H
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/select.h>
+extern int select();
+
+#endif
diff --git a/setup.do b/setup.do
new file mode 100644
index 0000000..d667234
--- /dev/null
+++ b/setup.do
@@ -0,0 +1,5 @@
+dependon it man install conf-bin conf-man BIN MAN
+formake './install "`head -1 conf-bin`" < BIN'
+formake './install "`head -1 conf-man`" < MAN'
+./install "`head -1 conf-bin`" < BIN
+./install "`head -1 conf-man`" < MAN
diff --git a/sgetopt.c b/sgetopt.c
new file mode 100644
index 0000000..a8bffc0
--- /dev/null
+++ b/sgetopt.c
@@ -0,0 +1,54 @@
+/* sgetopt.c, sgetopt.h: (yet another) improved getopt clone, outer layer
+D. J. Bernstein, djb@pobox.com.
+Depends on subgetopt.h, substdio.h, subfd.h.
+No system requirements.
+19970208: Cleanups.
+931201: Baseline.
+No known patent problems.
+
+Documentation in sgetopt.3.
+*/
+
+#include "substdio.h"
+#include "subfd.h"
+#define SGETOPTNOSHORT
+#include "sgetopt.h"
+#define SUBGETOPTNOSHORT
+#include "subgetopt.h"
+
+#define getopt sgetoptmine
+#define optind subgetoptind
+#define opterr sgetopterr
+#define optproblem subgetoptproblem
+#define optprogname sgetoptprogname
+
+int opterr = 1;
+char *optprogname = 0;
+
+int getopt(argc,argv,opts)
+int argc;
+char **argv;
+char *opts;
+{
+ int c;
+ char *s;
+
+ if (!optprogname) {
+ optprogname = *argv;
+ if (!optprogname) optprogname = "";
+ for (s = optprogname;*s;++s) if (*s == '/') optprogname = s + 1;
+ }
+ c = subgetopt(argc,argv,opts);
+ if (opterr)
+ if (c == '?') {
+ char chp[2]; chp[0] = optproblem; chp[1] = '\n';
+ substdio_puts(subfderr,optprogname);
+ if (argv[optind] && (optind < argc))
+ substdio_puts(subfderr,": illegal option -- ");
+ else
+ substdio_puts(subfderr,": option requires an argument -- ");
+ substdio_put(subfderr,chp,2);
+ substdio_flush(subfderr);
+ }
+ return c;
+}
diff --git a/sgetopt.h b/sgetopt.h
new file mode 100644
index 0000000..5f89127
--- /dev/null
+++ b/sgetopt.h
@@ -0,0 +1,21 @@
+#ifndef SGETOPT_H
+#define SGETOPT_H
+
+#ifndef SGETOPTNOSHORT
+#define getopt sgetoptmine
+#define optarg subgetoptarg
+#define optind subgetoptind
+#define optpos subgetoptpos
+#define opterr sgetopterr
+#define optproblem subgetoptproblem
+#define optprogname sgetoptprogname
+#define opteof subgetoptdone
+#endif
+
+#include "subgetopt.h"
+
+extern int sgetoptmine();
+extern int sgetopterr;
+extern char *sgetoptprogname;
+
+#endif
diff --git a/sig.h b/sig.h
new file mode 100644
index 0000000..9c3a28c
--- /dev/null
+++ b/sig.h
@@ -0,0 +1,43 @@
+#ifndef SIG_H
+#define SIG_H
+
+extern void sig_catch();
+extern void sig_block();
+extern void sig_unblock();
+extern void sig_blocknone();
+extern void sig_pause();
+
+extern void sig_dfl();
+
+extern void sig_miscignore();
+extern void sig_bugcatch();
+
+extern void sig_pipeignore();
+extern void sig_pipedefault();
+
+extern void sig_contblock();
+extern void sig_contunblock();
+extern void sig_contcatch();
+extern void sig_contdefault();
+
+extern void sig_termblock();
+extern void sig_termunblock();
+extern void sig_termcatch();
+extern void sig_termdefault();
+
+extern void sig_alarmblock();
+extern void sig_alarmunblock();
+extern void sig_alarmcatch();
+extern void sig_alarmdefault();
+
+extern void sig_childblock();
+extern void sig_childunblock();
+extern void sig_childcatch();
+extern void sig_childdefault();
+
+extern void sig_hangupblock();
+extern void sig_hangupunblock();
+extern void sig_hangupcatch();
+extern void sig_hangupdefault();
+
+#endif
diff --git a/sig=l b/sig=l
new file mode 100644
index 0000000..1cf813c
--- /dev/null
+++ b/sig=l
@@ -0,0 +1,7 @@
+sig_block.o
+sig_catch.o
+sig_pause.o
+sig_dfl.o
+sig_pipe.o
+sig_child.o
+sig_term.o
diff --git a/sig_block.c b/sig_block.c
new file mode 100644
index 0000000..c6b096a
--- /dev/null
+++ b/sig_block.c
@@ -0,0 +1,40 @@
+#include <signal.h>
+#include "sig.h"
+#include "hassgprm.h"
+
+void sig_block(sig)
+int sig;
+{
+#ifdef HASSIGPROCMASK
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigaddset(&ss,sig);
+ sigprocmask(SIG_BLOCK,&ss,(sigset_t *) 0);
+#else
+ sigblock(1 << (sig - 1));
+#endif
+}
+
+void sig_unblock(sig)
+int sig;
+{
+#ifdef HASSIGPROCMASK
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigaddset(&ss,sig);
+ sigprocmask(SIG_UNBLOCK,&ss,(sigset_t *) 0);
+#else
+ sigsetmask(sigsetmask(~0) & ~(1 << (sig - 1)));
+#endif
+}
+
+void sig_blocknone()
+{
+#ifdef HASSIGPROCMASK
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0);
+#else
+ sigsetmask(0);
+#endif
+}
diff --git a/sig_catch.c b/sig_catch.c
new file mode 100644
index 0000000..1888765
--- /dev/null
+++ b/sig_catch.c
@@ -0,0 +1,18 @@
+#include <signal.h>
+#include "sig.h"
+#include "hassgact.h"
+
+void sig_catch(sig,f)
+int sig;
+void (*f)();
+{
+#ifdef HASSIGACTION
+ struct sigaction sa;
+ sa.sa_handler = f;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(sig,&sa,(struct sigaction *) 0);
+#else
+ signal(sig,f); /* won't work under System V, even nowadays---dorks */
+#endif
+}
diff --git a/sig_child.c b/sig_child.c
new file mode 100644
index 0000000..fd5b39b
--- /dev/null
+++ b/sig_child.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include "sig.h"
+
+void sig_childblock() { sig_block(SIGCHLD); }
+void sig_childunblock() { sig_unblock(SIGCHLD); }
+void sig_childcatch(f) void (*f)(); { sig_catch(SIGCHLD,f); }
+void sig_childdefault() { sig_catch(SIGCHLD,SIG_DFL); }
diff --git a/sig_cont.c b/sig_cont.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sig_cont.c
diff --git a/sig_dfl.c b/sig_dfl.c
new file mode 100644
index 0000000..a92bd7b
--- /dev/null
+++ b/sig_dfl.c
@@ -0,0 +1,82 @@
+#include <signal.h>
+#include "sig.h"
+#include "hassgact.h"
+#include "hassgprm.h"
+
+/* tnx to Chris Torek for some improvements in previous versions */
+
+static int flagcont;
+
+static void sigcont() { flagcont = 1; }
+
+void sig_dfl(sig)
+int sig;
+{
+#ifdef HASSIGPROCMASK
+ sigset_t ssorig;
+ sigset_t ssnew;
+#else
+ int maskorig;
+ int masknew;
+#endif
+#ifdef HASSIGACTION
+ struct sigaction saorig;
+ struct sigaction sanew;
+#else
+ struct sigvec svorig;
+ struct sigvec svnew;
+#endif
+
+ if (sig == SIGCONT) return;
+
+#ifdef HASSIGPROCMASK
+ sigfillset(&ssnew);
+ sigprocmask(SIG_SETMASK,&ssnew,&ssorig);
+#else
+ masknew = ~0;
+ maskorig = sigsetmask(masknew);
+#endif
+
+#ifdef HASSIGACTION
+ sanew.sa_handler = SIG_DFL;
+ sanew.sa_flags = 0;
+ sigemptyset(&sanew.sa_mask);
+ sigaction(sig,&sanew,&saorig);
+ sanew.sa_handler = sigcont;
+ sigaction(SIGCONT,&sanew,(struct sigaction *) 0);
+#else
+ svnew.sv_handler = SIG_DFL;
+ svnew.sv_flags = 0;
+ svnew.sv_mask = 0;
+ sigvec(sig,&svnew,&svorig);
+ svnew.sv_handler = sigcont;
+ sigvec(SIGCONT,&svnew,(struct sigvec *) 0);
+#endif
+
+ flagcont = 0;
+ if (kill(getpid(),sig) == 0) {
+#ifdef HASSIGPROCMASK
+ sigdelset(&ssnew,sig);
+ sigdelset(&ssnew,SIGCONT);
+ while (!flagcont)
+ sigsuspend(&ssnew);
+#else
+ masknew &= ~(1 << (sig - 1));
+ masknew &= ~(1 << (SIGCONT - 1));
+ while (!flagcont)
+ sigpause(masknew);
+#endif
+ }
+
+#ifdef HASSIGACTION
+ sigaction(sig,&saorig,(struct sigaction *) 0);
+#else
+ sigvec(sig,&svorig,(struct sigvec *) 0);
+#endif
+
+#ifdef HASSIGPROCMASK
+ sigprocmask(SIG_SETMASK,&ssorig,(sigset_t *) 0);
+#else
+ sigsetmask(maskorig);
+#endif
+}
diff --git a/sig_pause.c b/sig_pause.c
new file mode 100644
index 0000000..3416734
--- /dev/null
+++ b/sig_pause.c
@@ -0,0 +1,14 @@
+#include <signal.h>
+#include "sig.h"
+#include "hassgprm.h"
+
+void sig_pause()
+{
+#ifdef HASSIGPROCMASK
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigsuspend(&ss);
+#else
+ sigpause(0);
+#endif
+}
diff --git a/sig_pipe.c b/sig_pipe.c
new file mode 100644
index 0000000..594ae7d
--- /dev/null
+++ b/sig_pipe.c
@@ -0,0 +1,5 @@
+#include <signal.h>
+#include "sig.h"
+
+void sig_pipeignore() { sig_catch(SIGPIPE,SIG_IGN); }
+void sig_pipedefault() { sig_catch(SIGPIPE,SIG_DFL); }
diff --git a/sig_term.c b/sig_term.c
new file mode 100644
index 0000000..ca72cc3
--- /dev/null
+++ b/sig_term.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include "sig.h"
+
+void sig_termblock() { sig_block(SIGTERM); }
+void sig_termunblock() { sig_unblock(SIGTERM); }
+void sig_termcatch(f) void (*f)(); { sig_catch(SIGTERM,f); }
+void sig_termdefault() { sig_catch(SIGTERM,SIG_DFL); }
diff --git a/socket.lib.do b/socket.lib.do
new file mode 100644
index 0000000..106c5e8
--- /dev/null
+++ b/socket.lib.do
@@ -0,0 +1,8 @@
+dependon trylsock.c compile load
+( ./compile trylsock.c && ./load trylsock -lsocket -lnsl ) >/dev/null 2>&1 \
+&& echo -lsocket -lnsl
+rm -f trylsock.o trylsock
+formake '( ( ./compile trylsock.c && \'
+formake './load trylsock -lsocket -lnsl ) >/dev/null 2>&1 \'
+formake '&& echo -lsocket -lnsl || exit 0 ) > socket.lib'
+formake 'rm -f trylsock.o trylsock'
diff --git a/str.h b/str.h
new file mode 100644
index 0000000..e00773c
--- /dev/null
+++ b/str.h
@@ -0,0 +1,14 @@
+#ifndef STR_H
+#define STR_H
+
+extern unsigned int str_copy();
+extern int str_diff();
+extern int str_diffn();
+extern unsigned int str_len();
+extern unsigned int str_chr();
+extern unsigned int str_rchr();
+extern int str_start();
+
+#define str_equal(s,t) (!str_diff((s),(t)))
+
+#endif
diff --git a/str=l b/str=l
new file mode 100644
index 0000000..26462e5
--- /dev/null
+++ b/str=l
@@ -0,0 +1,10 @@
+str_len.o
+str_diff.o
+str_diffn.o
+str_cpy.o
+byte_chr.o
+byte_rchr.o
+byte_diff.o
+byte_copy.o
+byte_cr.o
+byte_zero.o
diff --git a/str_cpy.c b/str_cpy.c
new file mode 100644
index 0000000..453d790
--- /dev/null
+++ b/str_cpy.c
@@ -0,0 +1,16 @@
+#include "str.h"
+
+unsigned int str_copy(s,t)
+register char *s;
+register char *t;
+{
+ register int len;
+
+ len = 0;
+ for (;;) {
+ if (!(*s = *t)) return len; ++s; ++t; ++len;
+ if (!(*s = *t)) return len; ++s; ++t; ++len;
+ if (!(*s = *t)) return len; ++s; ++t; ++len;
+ if (!(*s = *t)) return len; ++s; ++t; ++len;
+ }
+}
diff --git a/str_diff.c b/str_diff.c
new file mode 100644
index 0000000..18f8927
--- /dev/null
+++ b/str_diff.c
@@ -0,0 +1,17 @@
+#include "str.h"
+
+int str_diff(s,t)
+register char *s;
+register char *t;
+{
+ register char x;
+
+ for (;;) {
+ x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ }
+ return ((int)(unsigned int)(unsigned char) x)
+ - ((int)(unsigned int)(unsigned char) *t);
+}
diff --git a/str_diffn.c b/str_diffn.c
new file mode 100644
index 0000000..89142f1
--- /dev/null
+++ b/str_diffn.c
@@ -0,0 +1,18 @@
+#include "str.h"
+
+int str_diffn(s,t,len)
+register char *s;
+register char *t;
+unsigned int len;
+{
+ register char x;
+
+ for (;;) {
+ if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ }
+ return ((int)(unsigned int)(unsigned char) x)
+ - ((int)(unsigned int)(unsigned char) *t);
+}
diff --git a/str_len.c b/str_len.c
new file mode 100644
index 0000000..2d2f88b
--- /dev/null
+++ b/str_len.c
@@ -0,0 +1,15 @@
+#include "str.h"
+
+unsigned int str_len(s)
+register char *s;
+{
+ register char *t;
+
+ t = s;
+ for (;;) {
+ if (!*t) return t - s; ++t;
+ if (!*t) return t - s; ++t;
+ if (!*t) return t - s; ++t;
+ if (!*t) return t - s; ++t;
+ }
+}
diff --git a/stralloc.h b/stralloc.h
new file mode 100644
index 0000000..fca496c
--- /dev/null
+++ b/stralloc.h
@@ -0,0 +1,21 @@
+#ifndef STRALLOC_H
+#define STRALLOC_H
+
+#include "gen_alloc.h"
+
+GEN_ALLOC_typedef(stralloc,char,s,len,a)
+
+extern int stralloc_ready();
+extern int stralloc_readyplus();
+extern int stralloc_copy();
+extern int stralloc_cat();
+extern int stralloc_copys();
+extern int stralloc_cats();
+extern int stralloc_copyb();
+extern int stralloc_catb();
+extern int stralloc_append(); /* beware: this takes a pointer to 1 char */
+extern int stralloc_starts();
+
+#define stralloc_0(sa) stralloc_append(sa,"")
+
+#endif
diff --git a/stralloc=l b/stralloc=l
new file mode 100644
index 0000000..e1ebc8d
--- /dev/null
+++ b/stralloc=l
@@ -0,0 +1,8 @@
+stralloc_eady.o
+stralloc_pend.o
+stralloc_copy.o
+stralloc_opys.o
+stralloc_opyb.o
+stralloc_cat.o
+stralloc_cats.o
+stralloc_catb.o
diff --git a/stralloc_arts.c b/stralloc_arts.c
new file mode 100644
index 0000000..1ccb5a4
--- /dev/null
+++ b/stralloc_arts.c
@@ -0,0 +1,12 @@
+#include "byte.h"
+#include "str.h"
+#include "stralloc.h"
+
+int stralloc_starts(sa,s)
+stralloc *sa;
+char *s;
+{
+ int len;
+ len = str_len(s);
+ return (sa->len >= len) && byte_equal(s,len,sa->s);
+}
diff --git a/stralloc_cat.c b/stralloc_cat.c
new file mode 100644
index 0000000..efbb112
--- /dev/null
+++ b/stralloc_cat.c
@@ -0,0 +1,9 @@
+#include "byte.h"
+#include "stralloc.h"
+
+int stralloc_cat(sato,safrom)
+stralloc *sato;
+stralloc *safrom;
+{
+ return stralloc_catb(sato,safrom->s,safrom->len);
+}
diff --git a/stralloc_catb.c b/stralloc_catb.c
new file mode 100644
index 0000000..67dbcc0
--- /dev/null
+++ b/stralloc_catb.c
@@ -0,0 +1,15 @@
+#include "stralloc.h"
+#include "byte.h"
+
+int stralloc_catb(sa,s,n)
+stralloc *sa;
+char *s;
+unsigned int n;
+{
+ if (!sa->s) return stralloc_copyb(sa,s,n);
+ if (!stralloc_readyplus(sa,n + 1)) return 0;
+ byte_copy(sa->s + sa->len,n,s);
+ sa->len += n;
+ sa->s[sa->len] = 'Z'; /* ``offensive programming'' */
+ return 1;
+}
diff --git a/stralloc_cats.c b/stralloc_cats.c
new file mode 100644
index 0000000..d300286
--- /dev/null
+++ b/stralloc_cats.c
@@ -0,0 +1,10 @@
+#include "byte.h"
+#include "str.h"
+#include "stralloc.h"
+
+int stralloc_cats(sa,s)
+stralloc *sa;
+char *s;
+{
+ return stralloc_catb(sa,s,str_len(s));
+}
diff --git a/stralloc_copy.c b/stralloc_copy.c
new file mode 100644
index 0000000..652aed6
--- /dev/null
+++ b/stralloc_copy.c
@@ -0,0 +1,9 @@
+#include "byte.h"
+#include "stralloc.h"
+
+int stralloc_copy(sato,safrom)
+stralloc *sato;
+stralloc *safrom;
+{
+ return stralloc_copyb(sato,safrom->s,safrom->len);
+}
diff --git a/stralloc_eady.c b/stralloc_eady.c
new file mode 100644
index 0000000..3a31f4b
--- /dev/null
+++ b/stralloc_eady.c
@@ -0,0 +1,6 @@
+#include "alloc.h"
+#include "stralloc.h"
+#include "gen_allocdefs.h"
+
+GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready)
+GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus)
diff --git a/stralloc_opyb.c b/stralloc_opyb.c
new file mode 100644
index 0000000..ac258b3
--- /dev/null
+++ b/stralloc_opyb.c
@@ -0,0 +1,14 @@
+#include "stralloc.h"
+#include "byte.h"
+
+int stralloc_copyb(sa,s,n)
+stralloc *sa;
+char *s;
+unsigned int n;
+{
+ if (!stralloc_ready(sa,n + 1)) return 0;
+ byte_copy(sa->s,n,s);
+ sa->len = n;
+ sa->s[n] = 'Z'; /* ``offensive programming'' */
+ return 1;
+}
diff --git a/stralloc_opys.c b/stralloc_opys.c
new file mode 100644
index 0000000..fdd7807
--- /dev/null
+++ b/stralloc_opys.c
@@ -0,0 +1,10 @@
+#include "byte.h"
+#include "str.h"
+#include "stralloc.h"
+
+int stralloc_copys(sa,s)
+stralloc *sa;
+char *s;
+{
+ return stralloc_copyb(sa,s,str_len(s));
+}
diff --git a/stralloc_pend.c b/stralloc_pend.c
new file mode 100644
index 0000000..a3443b8
--- /dev/null
+++ b/stralloc_pend.c
@@ -0,0 +1,5 @@
+#include "alloc.h"
+#include "stralloc.h"
+#include "gen_allocdefs.h"
+
+GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append)
diff --git a/strerr.h b/strerr.h
new file mode 100644
index 0000000..d18e833
--- /dev/null
+++ b/strerr.h
@@ -0,0 +1,80 @@
+#ifndef STRERR_H
+#define STRERR_H
+
+struct strerr
+ {
+ struct strerr *who;
+ char *x;
+ char *y;
+ char *z;
+ }
+;
+
+extern struct strerr strerr_sys;
+extern void strerr_sysinit();
+
+extern char *strerr();
+extern void strerr_warn();
+extern void strerr_die();
+
+#define STRERR(r,se,a) \
+{ se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; }
+
+#define STRERR_SYS(r,se,a) \
+{ se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; }
+#define STRERR_SYS3(r,se,a,b,c) \
+{ se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; }
+
+#define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \
+strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se))
+#define strerr_warn5(x1,x2,x3,x4,x5,se) \
+strerr_warn((x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se))
+#define strerr_warn4(x1,x2,x3,x4,se) \
+strerr_warn((x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_warn3(x1,x2,x3,se) \
+strerr_warn((x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_warn2(x1,x2,se) \
+strerr_warn((x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_warn1(x1,se) \
+strerr_warn((x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+
+#define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se))
+#define strerr_die5(e,x1,x2,x3,x4,x5,se) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se))
+#define strerr_die4(e,x1,x2,x3,x4,se) \
+strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_die3(e,x1,x2,x3,se) \
+strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_die2(e,x1,x2,se) \
+strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_die1(e,x1,se) \
+strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+
+#define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys)
+#define strerr_die5sys(e,x1,x2,x3,x4,x5) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,&strerr_sys)
+#define strerr_die4sys(e,x1,x2,x3,x4) \
+strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,&strerr_sys)
+#define strerr_die3sys(e,x1,x2,x3) \
+strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,&strerr_sys)
+#define strerr_die2sys(e,x1,x2) \
+strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys)
+#define strerr_die1sys(e,x1) \
+strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys)
+
+#define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) 0)
+#define strerr_die5x(e,x1,x2,x3,x4,x5) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) 0)
+#define strerr_die4x(e,x1,x2,x3,x4) \
+strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) 0)
+#define strerr_die3x(e,x1,x2,x3) \
+strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0)
+#define strerr_die2x(e,x1,x2) \
+strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0)
+#define strerr_die1x(e,x1) \
+strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0)
+
+#endif
diff --git a/strerr=l b/strerr=l
new file mode 100644
index 0000000..5181cee
--- /dev/null
+++ b/strerr=l
@@ -0,0 +1,2 @@
+strerr_sys.o
+strerr_die.o
diff --git a/strerr_die.c b/strerr_die.c
new file mode 100644
index 0000000..6092020
--- /dev/null
+++ b/strerr_die.c
@@ -0,0 +1,37 @@
+#include "substdio.h"
+#include "subfd.h"
+#include "exit.h"
+#include "strerr.h"
+
+void strerr_warn(x1,x2,x3,x4,x5,x6,se)
+char *x1; char *x2; char *x3; char *x4; char *x5; char *x6;
+struct strerr *se;
+{
+ strerr_sysinit();
+
+ if (x1) substdio_puts(subfderr,x1);
+ if (x2) substdio_puts(subfderr,x2);
+ if (x3) substdio_puts(subfderr,x3);
+ if (x4) substdio_puts(subfderr,x4);
+ if (x5) substdio_puts(subfderr,x5);
+ if (x6) substdio_puts(subfderr,x6);
+
+ while(se) {
+ if (se->x) substdio_puts(subfderr,se->x);
+ if (se->y) substdio_puts(subfderr,se->y);
+ if (se->z) substdio_puts(subfderr,se->z);
+ se = se->who;
+ }
+
+ substdio_puts(subfderr,"\n");
+ substdio_flush(subfderr);
+}
+
+void strerr_die(e,x1,x2,x3,x4,x5,x6,se)
+int e;
+char *x1; char *x2; char *x3; char *x4; char *x5; char *x6;
+struct strerr *se;
+{
+ strerr_warn(x1,x2,x3,x4,x5,x6,se);
+ _exit(e);
+}
diff --git a/strerr_sys.c b/strerr_sys.c
new file mode 100644
index 0000000..198198b
--- /dev/null
+++ b/strerr_sys.c
@@ -0,0 +1,12 @@
+#include "error.h"
+#include "strerr.h"
+
+struct strerr strerr_sys;
+
+void strerr_sysinit()
+{
+ strerr_sys.who = 0;
+ strerr_sys.x = error_str(errno);
+ strerr_sys.y = "";
+ strerr_sys.z = "";
+}
diff --git a/subfd.h b/subfd.h
new file mode 100644
index 0000000..bcb2e1e
--- /dev/null
+++ b/subfd.h
@@ -0,0 +1,15 @@
+#ifndef SUBFD_H
+#define SUBFD_H
+
+#include "substdio.h"
+
+extern substdio *subfdin;
+extern substdio *subfdinsmall;
+extern substdio *subfdout;
+extern substdio *subfdoutsmall;
+extern substdio *subfderr;
+
+extern int subfd_read();
+extern int subfd_readsmall();
+
+#endif
diff --git a/subfderr.c b/subfderr.c
new file mode 100644
index 0000000..011ab0f
--- /dev/null
+++ b/subfderr.c
@@ -0,0 +1,7 @@
+#include "readwrite.h"
+#include "substdio.h"
+#include "subfd.h"
+
+char subfd_errbuf[256];
+static substdio it = SUBSTDIO_FDBUF(write,2,subfd_errbuf,256);
+substdio *subfderr = &it;
diff --git a/subfdin.c b/subfdin.c
new file mode 100644
index 0000000..a11d323
--- /dev/null
+++ b/subfdin.c
@@ -0,0 +1,13 @@
+#include "readwrite.h"
+#include "substdio.h"
+#include "subfd.h"
+
+int subfd_read(fd,buf,len) int fd; char *buf; int len;
+{
+ if (substdio_flush(subfdout) == -1) return -1;
+ return read(fd,buf,len);
+}
+
+char subfd_inbuf[SUBSTDIO_INSIZE];
+static substdio it = SUBSTDIO_FDBUF(subfd_read,0,subfd_inbuf,SUBSTDIO_INSIZE);
+substdio *subfdin = &it;
diff --git a/subfdout.c b/subfdout.c
new file mode 100644
index 0000000..0aee102
--- /dev/null
+++ b/subfdout.c
@@ -0,0 +1,7 @@
+#include "readwrite.h"
+#include "substdio.h"
+#include "subfd.h"
+
+char subfd_outbuf[SUBSTDIO_OUTSIZE];
+static substdio it = SUBSTDIO_FDBUF(write,1,subfd_outbuf,SUBSTDIO_OUTSIZE);
+substdio *subfdout = &it;
diff --git a/subgetopt.c b/subgetopt.c
new file mode 100644
index 0000000..dacf376
--- /dev/null
+++ b/subgetopt.c
@@ -0,0 +1,79 @@
+/* subgetopt.c, subgetopt.h: (yet another) improved getopt clone, inner layer
+D. J. Bernstein, djb@pobox.com.
+No dependencies.
+No system requirements.
+19970228: Cleanups.
+931129: Adapted from getopt.c.
+No known patent problems.
+
+Documentation in subgetopt.3.
+*/
+
+#define SUBGETOPTNOSHORT
+#include "subgetopt.h"
+
+#define sgopt subgetopt
+#define optind subgetoptind
+#define optpos subgetoptpos
+#define optarg subgetoptarg
+#define optproblem subgetoptproblem
+#define optdone subgetoptdone
+
+int optind = 1;
+int optpos = 0;
+char *optarg = 0;
+int optproblem = 0;
+int optdone = SUBGETOPTDONE;
+
+int sgopt(argc,argv,opts)
+int argc;
+char **argv;
+char *opts;
+{
+ int c;
+ char *s;
+
+ optarg = 0;
+ if (!argv || (optind >= argc) || !argv[optind]) return optdone;
+ if (optpos && !argv[optind][optpos]) {
+ ++optind;
+ optpos = 0;
+ if ((optind >= argc) || !argv[optind]) return optdone;
+ }
+ if (!optpos) {
+ if (argv[optind][0] != '-') return optdone;
+ ++optpos;
+ c = argv[optind][1];
+ if ((c == '-') || (c == 0)) {
+ if (c) ++optind;
+ optpos = 0;
+ return optdone;
+ }
+ /* otherwise c is reassigned below */
+ }
+ c = argv[optind][optpos];
+ ++optpos;
+ s = opts;
+ while (*s) {
+ if (c == *s) {
+ if (s[1] == ':') {
+ optarg = argv[optind] + optpos;
+ ++optind;
+ optpos = 0;
+ if (!*optarg) {
+ optarg = argv[optind];
+ if ((optind >= argc) || !optarg) { /* argument past end */
+ optproblem = c;
+ return '?';
+ }
+ ++optind;
+ }
+ }
+ return c;
+ }
+ ++s;
+ if (*s == ':') ++s;
+ }
+ optproblem = c;
+ return '?';
+}
diff --git a/subgetopt.h b/subgetopt.h
new file mode 100644
index 0000000..d26c62a
--- /dev/null
+++ b/subgetopt.h
@@ -0,0 +1,24 @@
+#ifndef SUBGETOPT_H
+#define SUBGETOPT_H
+
+#ifndef SUBGETOPTNOSHORT
+#define sgopt subgetopt
+#define sgoptarg subgetoptarg
+#define sgoptind subgetoptind
+#define sgoptpos subgetoptpos
+#define sgoptproblem subgetoptproblem
+#define sgoptprogname subgetoptprogname
+#define sgoptdone subgetoptdone
+#endif
+
+#define SUBGETOPTDONE -1
+
+extern int subgetopt();
+extern char *subgetoptarg;
+extern int subgetoptind;
+extern int subgetoptpos;
+extern int subgetoptproblem;
+extern char *subgetoptprogname;
+extern int subgetoptdone;
+
+#endif
diff --git a/substdi.c b/substdi.c
new file mode 100644
index 0000000..42407a1
--- /dev/null
+++ b/substdi.c
@@ -0,0 +1,91 @@
+#include "substdio.h"
+#include "byte.h"
+#include "error.h"
+
+static int oneread(op,fd,buf,len)
+register int (*op)();
+register int fd;
+register char *buf;
+register int len;
+{
+ register int r;
+
+ for (;;) {
+ r = op(fd,buf,len);
+ if (r == -1) if (errno == error_intr) continue;
+ return r;
+ }
+}
+
+static int getthis(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int r;
+ register int q;
+
+ r = s->p;
+ q = r - len;
+ if (q > 0) { r = len; s->p = q; } else s->p = 0;
+ byte_copy(buf,r,s->x + s->n);
+ s->n += r;
+ return r;
+}
+
+int substdio_feed(s)
+register substdio *s;
+{
+ register int r;
+ register int q;
+
+ if (s->p) return s->p;
+ q = s->n;
+ r = oneread(s->op,s->fd,s->x,q);
+ if (r <= 0) return r;
+ s->p = r;
+ q -= r;
+ s->n = q;
+ if (q > 0) /* damn, gotta shift */ byte_copyr(s->x + q,r,s->x);
+ return r;
+}
+
+int substdio_bget(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int r;
+
+ if (s->p > 0) return getthis(s,buf,len);
+ r = s->n; if (r <= len) return oneread(s->op,s->fd,buf,r);
+ r = substdio_feed(s); if (r <= 0) return r;
+ return getthis(s,buf,len);
+}
+
+int substdio_get(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int r;
+
+ if (s->p > 0) return getthis(s,buf,len);
+ if (s->n <= len) return oneread(s->op,s->fd,buf,len);
+ r = substdio_feed(s); if (r <= 0) return r;
+ return getthis(s,buf,len);
+}
+
+char *substdio_peek(s)
+register substdio *s;
+{
+ return s->x + s->n;
+}
+
+void substdio_seek(s,len)
+register substdio *s;
+register int len;
+{
+ s->n += len;
+ s->p -= len;
+}
diff --git a/substdio.c b/substdio.c
new file mode 100644
index 0000000..d03dff2
--- /dev/null
+++ b/substdio.c
@@ -0,0 +1,15 @@
+#include "substdio.h"
+
+void substdio_fdbuf(s,op,fd,buf,len)
+register substdio *s;
+register int (*op)();
+register int fd;
+register char *buf;
+register int len;
+{
+ s->x = buf;
+ s->fd = fd;
+ s->op = op;
+ s->p = 0;
+ s->n = len;
+}
diff --git a/substdio.h b/substdio.h
new file mode 100644
index 0000000..c3f7f7d
--- /dev/null
+++ b/substdio.h
@@ -0,0 +1,47 @@
+#ifndef SUBSTDIO_H
+#define SUBSTDIO_H
+
+typedef struct substdio {
+ char *x;
+ int p;
+ int n;
+ int fd;
+ int (*op)();
+} substdio;
+
+#define SUBSTDIO_FDBUF(op,fd,buf,len) { (buf), 0, (len), (fd), (op) }
+
+extern void substdio_fdbuf();
+
+extern int substdio_flush();
+extern int substdio_put();
+extern int substdio_bput();
+extern int substdio_putflush();
+extern int substdio_puts();
+extern int substdio_bputs();
+extern int substdio_putsflush();
+
+extern int substdio_get();
+extern int substdio_bget();
+extern int substdio_feed();
+
+extern char *substdio_peek();
+extern void substdio_seek();
+
+#define substdio_fileno(s) ((s)->fd)
+
+#define SUBSTDIO_INSIZE 8192
+#define SUBSTDIO_OUTSIZE 8192
+
+#define substdio_PEEK(s) ( (s)->x + (s)->n )
+#define substdio_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) )
+
+#define substdio_BPUTC(s,c) \
+ ( ((s)->n != (s)->p) \
+ ? ( (s)->x[(s)->p++] = (c), 0 ) \
+ : substdio_bput((s),&(c),1) \
+ )
+
+extern int substdio_copy();
+
+#endif
diff --git a/substdio=l b/substdio=l
new file mode 100644
index 0000000..55720b5
--- /dev/null
+++ b/substdio=l
@@ -0,0 +1,7 @@
+substdio.o
+substdi.o
+substdo.o
+subfderr.o
+subfdout.o
+subfdin.o
+substdio_copy.o
diff --git a/substdio_copy.c b/substdio_copy.c
new file mode 100644
index 0000000..71cf200
--- /dev/null
+++ b/substdio_copy.c
@@ -0,0 +1,18 @@
+#include "substdio.h"
+
+int substdio_copy(ssout,ssin)
+register substdio *ssout;
+register substdio *ssin;
+{
+ register int n;
+ register char *x;
+
+ for (;;) {
+ n = substdio_feed(ssin);
+ if (n < 0) return -2;
+ if (!n) return 0;
+ x = substdio_PEEK(ssin);
+ if (substdio_put(ssout,x,n) == -1) return -3;
+ substdio_SEEK(ssin,n);
+ }
+}
diff --git a/substdo.c b/substdo.c
new file mode 100644
index 0000000..fb616f7
--- /dev/null
+++ b/substdo.c
@@ -0,0 +1,108 @@
+#include "substdio.h"
+#include "str.h"
+#include "byte.h"
+#include "error.h"
+
+static int allwrite(op,fd,buf,len)
+register int (*op)();
+register int fd;
+register char *buf;
+register int len;
+{
+ register int w;
+
+ while (len) {
+ w = op(fd,buf,len);
+ if (w == -1) {
+ if (errno == error_intr) continue;
+ return -1; /* note that some data may have been written */
+ }
+ if (w == 0) ; /* luser's fault */
+ buf += w;
+ len -= w;
+ }
+ return 0;
+}
+
+int substdio_flush(s)
+register substdio *s;
+{
+ register int p;
+
+ p = s->p;
+ if (!p) return 0;
+ s->p = 0;
+ return allwrite(s->op,s->fd,s->x,p);
+}
+
+int substdio_bput(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int n;
+
+ while (len > (n = s->n - s->p)) {
+ byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n;
+ if (substdio_flush(s) == -1) return -1;
+ }
+ /* now len <= s->n - s->p */
+ byte_copy(s->x + s->p,len,buf);
+ s->p += len;
+ return 0;
+}
+
+int substdio_put(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int n;
+
+ n = s->n;
+ if (len > n - s->p) {
+ if (substdio_flush(s) == -1) return -1;
+ /* now s->p == 0 */
+ if (n < SUBSTDIO_OUTSIZE) n = SUBSTDIO_OUTSIZE;
+ while (len > s->n) {
+ if (n > len) n = len;
+ if (allwrite(s->op,s->fd,buf,n) == -1) return -1;
+ buf += n;
+ len -= n;
+ }
+ }
+ /* now len <= s->n - s->p */
+ byte_copy(s->x + s->p,len,buf);
+ s->p += len;
+ return 0;
+}
+
+int substdio_putflush(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ if (substdio_flush(s) == -1) return -1;
+ return allwrite(s->op,s->fd,buf,len);
+}
+
+int substdio_bputs(s,buf)
+register substdio *s;
+register char *buf;
+{
+ return substdio_bput(s,buf,str_len(buf));
+}
+
+int substdio_puts(s,buf)
+register substdio *s;
+register char *buf;
+{
+ return substdio_put(s,buf,str_len(buf));
+}
+
+int substdio_putsflush(s,buf)
+register substdio *s;
+register char *buf;
+{
+ return substdio_putflush(s,buf,str_len(buf));
+}
diff --git a/tcp-environ.5 b/tcp-environ.5
new file mode 100644
index 0000000..b5cb83b
--- /dev/null
+++ b/tcp-environ.5
@@ -0,0 +1,62 @@
+.TH tcp-environ 5
+.SH NAME
+tcp-environ \- TCP-related environment variables
+.SH DESCRIPTION
+The following environment variables
+describe a TCP connection.
+They are set up by
+.BR tcp-env ,
+.BR tcpclient ,
+and
+.BR tcpserver .
+Note that
+.BR TCPLOCALHOST ,
+.BR TCPREMOTEHOST ,
+and
+.B TCPREMOTEINFO
+can contain arbitrary characters.
+.TP 5
+PROTO
+The string
+.BR TCP .
+.TP 5
+TCPLOCALHOST
+The domain name of the local host,
+with uppercase letters converted to lowercase.
+If there is no currently available domain name
+for the local IP address,
+.B TCPLOCALHOST
+is not set.
+.TP 5
+TCPLOCALIP
+The IP address of the local host, in dotted-decimal form.
+.TP 5
+TCPLOCALPORT
+The local TCP port number, in decimal.
+.TP 5
+TCPREMOTEHOST
+The domain name of the remote host,
+with uppercase letters converted to lowercase.
+If there is no currently available domain name
+for the remote IP address,
+.B TCPREMOTEHOST
+is not set.
+.TP 5
+TCPREMOTEINFO
+A connection-specific string, perhaps a username,
+supplied by the remote host
+via 931/1413/IDENT/TAP.
+If the remote host did not supply connection information,
+.B TCPREMOTEINFO
+is not set.
+.TP 5
+TCPREMOTEIP
+The IP address of the remote host.
+.TP 5
+TCPREMOTEPORT
+The remote TCP port number.
+.SH "SEE ALSO"
+tcpclient(1),
+tcpserver(1),
+tcp-env(1),
+tcp(4)
diff --git a/tcp-environ=0 b/tcp-environ=0
new file mode 100644
index 0000000..da3c189
--- /dev/null
+++ b/tcp-environ=0
@@ -0,0 +1 @@
+tcp-environ.5
diff --git a/tcpcat.sh b/tcpcat.sh
new file mode 100644
index 0000000..485cb26
--- /dev/null
+++ b/tcpcat.sh
@@ -0,0 +1 @@
+exec BIN/tcpclient -RHl0 -- "${1-0}" "${2-17}" sh -c 'exec cat <&6'
diff --git a/tcpcat=s b/tcpcat=s
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tcpcat=s
diff --git a/tcpclient.1 b/tcpclient.1
new file mode 100644
index 0000000..9c91902
--- /dev/null
+++ b/tcpclient.1
@@ -0,0 +1,134 @@
+.TH tcpclient 1
+.SH NAME
+tcpclient \- create an outgoing TCP connection
+.SH SYNOPSIS
+.B tcpclient
+[
+.B \-qQvdDhHrR
+]
+[
+.B \-l\fIlocalname
+]
+[
+.B \-p\fIlocport
+]
+[
+.B \-t\fItimeoutinfo
+]
+[
+.B \-T\fItimeoutconn
+]
+.I host
+.I port
+.I program
+[
+.I arg ...
+]
+.SH DESCRIPTION
+.B tcpclient
+is a TCP UCSPI client.
+It attempts to connect to a TCP server;
+if it is successful, it runs
+.I program
+with the given arguments,
+with descriptor 6 reading from the network
+and descriptor 7 writing to the network.
+
+The server's address is given by
+.I host
+and
+.IR port .
+.I host
+may be 0, referring to the local machine,
+or a dotted-decimal IP address,
+or a host name;
+if a host has several IP addresses,
+.B tcpclient
+tries each in turn.
+.I port
+may be a numeric port number
+or a port name.
+
+.B tcpclient
+sets up several environment variables,
+as described in
+.B tcp-environ(5).
+.SH OPTIONS
+.TP
+.B \-p\fIlocport
+Use
+.I locport
+for the local side of the connection;
+quit if
+.I locport
+is not available.
+.TP
+.B \-q
+Quiet.
+Do not print any messages.
+.TP
+.B \-Q
+(Default.)
+Print error messages.
+.TP
+.B \-v
+Verbose.
+Print all available messages.
+.TP
+.B \-T\fItimeoutconn
+Give up on the
+connection attempt
+after
+.I timeoutconn
+seconds. Default: 60.
+This timeout applies to each IP address tried.
+.TP
+.B \-h
+(Default.)
+Look up the remote host name for
+.BR TCPREMOTEHOST .
+.TP
+.B \-H
+Do not look up the remote host name;
+unset
+.BR TCPREMOTEHOST .
+.TP
+.B \-l\fIlocalname
+Do not look up the local host name;
+use
+.I localname
+for
+.BR TCPLOCALHOST .
+.TP
+.B \-r
+(Default.)
+Attempt to obtain
+.B TCPREMOTEINFO
+from the remote host.
+.TP
+.B \-R
+Do not attempt to obtain
+.B TCPREMOTEINFO
+from the remote host.
+.TP
+.B \-t\fItimeoutinfo
+Give up on the
+.B TCPREMOTEINFO
+connection attempt
+after
+.I timeoutinfo
+seconds. Default: 26.
+.TP
+.B \-d
+(Default.)
+Delay sending data for a fraction of a second whenever the
+remote host is responding slowly,
+to make better use of the network.
+.TP
+.B \-D
+Never delay sending data;
+enable TCP_NODELAY.
+This is appropriate for interactive connections.
+.SH "SEE ALSO"
+tcpserver(1),
+tcp-environ(5)
diff --git a/tcpclient.c b/tcpclient.c
new file mode 100644
index 0000000..a22a20a
--- /dev/null
+++ b/tcpclient.c
@@ -0,0 +1,236 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "substdio.h"
+#include "stralloc.h"
+#include "str.h"
+#include "byte.h"
+#include "error.h"
+#include "sig.h"
+#include "subfd.h"
+#include "fd.h"
+#include "ip.h"
+#include "ipalloc.h"
+#include "case.h"
+#include "sgetopt.h"
+#include "exit.h"
+#include "scan.h"
+#include "fmt.h"
+#include "env.h"
+#include "dns.h"
+#include "remoteinfo.h"
+
+int verbosity = 1;
+char temp[IPFMT + FMT_ULONG];
+
+void out(s) char *s; { if (verbosity) substdio_puts(subfderr,s); }
+void flush() { if (verbosity) substdio_flush(subfderr); }
+
+void usage()
+{ out("tcpclient: usage: \
+tcpclient [ -qQvdDrRU ] [ -plocport ] [ -llocalname ] [ -ttimeoutinfo ] \
+[ -Ttimeoutconn ] host port program\n"); flush(); _exit(100); }
+void die(s) char *s;
+{ out("tcpclient: fatal: "); out(s); out("\n"); flush(); _exit(111); }
+void diep(s) char *s;
+{ char *x = error_str(errno);
+ out("tcpclient: fatal: "); out(s); out(": ");
+ out(x); out("\n"); flush(); _exit(111); }
+void nomem()
+{ die("out of memory"); }
+void warnconnect(ipr) struct ip_address *ipr;
+{
+ char *x = error_str(errno);
+ temp[ip_fmt(temp,ipr)] = 0;
+ out("tcpclient: unable to connect to "); out(temp); out(": ");
+ out(x); out("\n"); flush(); }
+void infoconnected(ipr) struct ip_address *ipr;
+{ if (verbosity < 2) return;
+ temp[ip_fmt(temp,ipr)] = 0;
+ out("tcpclient: connected to "); out(temp); out("\n"); flush(); }
+
+int flagdelay = 1;
+int flagremoteinfo = 1;
+int flagremotehost = 1;
+char *forcelocal = 0;
+unsigned long timeout = 26;
+unsigned long timeout2 = 60;
+
+stralloc tmp = {0};
+ipalloc ia = {0};
+
+struct sockaddr_in salocal;
+struct ip_address iplocal;
+unsigned long portlocal;
+struct sockaddr_in saremote;
+struct ip_address ipremote;
+unsigned long portremote;
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+ int s;
+ int dummy;
+ int opt;
+ char *hostname;
+ char *portname;
+ struct servent *se;
+ int j;
+
+ portlocal = 0;
+
+ while ((opt = getopt(argc,argv,"dDvqQLhHrRp:Ut:T:l:")) != opteof)
+ switch(opt) {
+ case 'd': flagdelay = 1; break;
+ case 'D': flagdelay = 0; break;
+ case 'v': verbosity = 2; break;
+ case 'q': verbosity = 0; break;
+ case 'Q': verbosity = 1; break;
+ case 'l': forcelocal = optarg; break;
+ case 'H': flagremotehost = 0; break;
+ case 'h': flagremotehost = 1; break;
+ case 'R': flagremoteinfo = 0; break;
+ case 'r': flagremoteinfo = 1; break;
+ case 'p': scan_ulong(optarg,&portlocal); break;
+ case 't': scan_ulong(optarg,&timeout); break;
+ case 'T': scan_ulong(optarg,&timeout2); break;
+ case 'U': usage();
+ default: _exit(100);
+ }
+ argc -= optind;
+ argv += optind;
+
+ hostname = *argv++;
+ if (!hostname) usage();
+ portname = *argv++;
+ if (!portname) usage();
+ if (!*argv) usage();
+
+ close(6);
+ close(7);
+ sig_pipeignore();
+
+ dns_init(1);
+
+ byte_zero(&salocal,sizeof(salocal));
+ salocal.sin_family = AF_INET;
+ salocal.sin_addr.s_addr = INADDR_ANY;
+ salocal.sin_port = htons((unsigned short) portlocal);
+
+ byte_zero(&saremote,sizeof(saremote));
+ saremote.sin_family = AF_INET;
+
+ if (!portname[scan_ulong(portname,&portremote)])
+ ;
+ else {
+ se = getservbyname(portname,"tcp");
+ if (!se) die("unable to figure out port number");
+ portremote = ntohs(se->s_port);
+ /* i continue to be amazed at the stupidity of the s_port interface */
+ }
+
+ if (!str_diff(hostname,"0")) hostname = "0.0.0.0";
+
+ if (!hostname[ip_scan(hostname,&ipremote)]) {
+ s = socket(AF_INET,SOCK_STREAM,0);
+ if (s == -1) diep("unable to create socket");
+ if (bind(s,(struct sockaddr *) &salocal,sizeof(salocal)) == -1)
+ diep("unable to bind");
+ if (timeoutconn(s,&ipremote,portremote,(int) timeout2) == -1) {
+ warnconnect(&ipremote);
+ _exit(111);
+ }
+ }
+ else {
+ if (!stralloc_copys(&tmp,hostname)) nomem();
+ switch(dns_ip(&ia,&tmp)) {
+ case DNS_SOFT: die("temporarily unable to figure out host address");
+ case DNS_HARD: die("unable to figure out host address");
+ case DNS_MEM: nomem();
+ }
+ if (ia.len == 0) die("no IP addresses for that host");
+ for (j = 0;j < ia.len;++j) {
+ s = socket(AF_INET,SOCK_STREAM,0);
+ if (s == -1) diep("unable to create socket");
+ if (bind(s,(struct sockaddr *) &salocal,sizeof(salocal)) == -1)
+ diep("unable to bind");
+ byte_copy(&ipremote,4,&ia.ix[j].ip);
+ if (timeoutconn(s,&ipremote,portremote,(int) timeout2) == 0) break;
+ warnconnect(&ipremote);
+ close(s);
+ }
+ if (j == ia.len) _exit(111);
+ }
+
+ if (!flagdelay) {
+ int opt = 1;
+ setsockopt(s,IPPROTO_TCP,1,&opt,sizeof(opt)); /* 1 == TCP_NODELAY */
+ /* if it fails, bummer */
+ }
+
+ if (!env_init()) nomem();
+ if (!env_put("PROTO=TCP")) nomem();
+ if (!env_unset("TCPLOCALHOST")) nomem();
+ if (!env_unset("TCPREMOTEHOST")) nomem();
+ if (!env_unset("TCPREMOTEINFO")) nomem();
+
+ dummy = sizeof(salocal);
+ if (getsockname(s,(struct sockaddr *) &salocal,&dummy) == -1)
+ diep("unable to get local address");
+ portlocal = ntohs(salocal.sin_port);
+ byte_copy(&iplocal,4,&salocal.sin_addr);
+
+ temp[fmt_ulong(temp,portlocal)] = 0;
+ if (!env_put2("TCPLOCALPORT",temp)) nomem();
+ temp[ip_fmt(temp,&iplocal)] = 0;
+ if (!env_put2("TCPLOCALIP",temp)) nomem();
+ if (forcelocal) {
+ if (!env_put2("TCPLOCALHOST",forcelocal)) nomem();
+ }
+ else
+ switch(dns_ptr(&tmp,&iplocal)) {
+ case DNS_MEM: nomem();
+ case 0:
+ if (!stralloc_0(&tmp)) nomem();
+ case_lowers(tmp.s);
+ if (!env_put2("TCPLOCALHOST",tmp.s)) nomem();
+ }
+
+ dummy = sizeof(saremote);
+ if (getpeername(s,(struct sockaddr *) &saremote,&dummy) == -1)
+ diep("unable to get remote address");
+ portremote = ntohs(saremote.sin_port);
+ byte_copy(&ipremote,4,&saremote.sin_addr);
+
+ infoconnected(&ipremote);
+
+ temp[fmt_ulong(temp,portremote)] = 0;
+ if (!env_put2("TCPREMOTEPORT",temp)) nomem();
+ temp[ip_fmt(temp,&ipremote)] = 0;
+ if (!env_put2("TCPREMOTEIP",temp)) nomem();
+ if (flagremotehost)
+ switch(dns_ptr(&tmp,&ipremote)) {
+ case DNS_MEM: nomem();
+ case 0:
+ if (!stralloc_0(&tmp)) nomem();
+ case_lowers(tmp.s);
+ if (!env_put2("TCPREMOTEHOST",tmp.s)) nomem();
+ }
+ if (flagremoteinfo) {
+ char *rinfo;
+ rinfo = remoteinfo_get(&ipremote,portremote,&iplocal,portlocal,(int) timeout);
+ if (rinfo)
+ if (!env_put2("TCPREMOTEINFO",rinfo)) nomem();
+ }
+
+ if (fd_move(6,s) == -1) diep("unable to set up descriptor 6");
+ if (fd_copy(7,6) == -1) diep("unable to set up descriptor 7");
+ sig_pipedefault();
+
+ execvp(*argv,argv);
+ diep("unable to execute");
+}
diff --git a/tcpclient=0 b/tcpclient=0
new file mode 100644
index 0000000..cea39bf
--- /dev/null
+++ b/tcpclient=0
@@ -0,0 +1 @@
+tcpclient.1
diff --git a/tcpclient=x b/tcpclient=x
new file mode 100644
index 0000000..569d485
--- /dev/null
+++ b/tcpclient=x
@@ -0,0 +1,21 @@
+ip.o
+ipalloc.o
+dns.o
+remoteinfo.o
+timeoutconn.o
+timeoutread.o
+timeoutwrite.o
+stralloc.a
+env.a
+alloc.a
+ndelay.a
+substdio.a
+error.a
+str.a
+sig.a
+fd.a
+case.a
+getopt.a
+fs.a
+dns.lib
+socket.lib
diff --git a/tcprules.1 b/tcprules.1
new file mode 100644
index 0000000..6bf8dcc
--- /dev/null
+++ b/tcprules.1
@@ -0,0 +1,207 @@
+.TH tcprules 1
+.SH NAME
+tcprules \- compile rules for tcpserver
+.SH SYNOPSIS
+.B tcprules
+.I rules.cdb
+.I rules.tmp
+.SH OVERVIEW
+.B tcpserver
+optionally follows rules to decide whether a TCP connection is acceptable.
+For example, a rule of
+
+.EX
+ 18.23.0.32:deny
+.EE
+
+prohibits connections from IP address 18.23.0.32.
+
+.B tcprules
+reads rules from its standard input
+and writes them into
+.I rules.cdb
+in a binary format suited
+for quick access by
+.BR tcpserver .
+
+.B tcprules
+can be used while
+.B tcpserver
+is running:
+it ensures that
+.I rules.cdb
+is updated atomically.
+It does this by first writing the rules to
+.I rules.tmp
+and then moving
+.I rules.tmp
+on top of
+.IR rules.cdb .
+If
+.I rules.tmp
+already exists, it is destroyed.
+The directories containing
+.I rules.cdb
+and
+.I rules.tmp
+must be writable to
+.BR tcprules ;
+they must also be on the same filesystem.
+
+If there is a problem with the input,
+.B tcprules
+complains and leaves
+.I rules.cdb
+alone.
+
+The binary
+.I rules.cdb
+format is portable across machines.
+.SH "RULE FORMAT"
+A rule takes up one line.
+A file containing rules
+may also contain comments: lines beginning with # are ignored.
+
+Each rule contains an
+.BR address ,
+a colon,
+and a list of
+.BR instructions ,
+with no extra spaces.
+When
+.B tcpserver
+receives a connection from that address,
+it follows the instructions.
+.SH "ADDRESSES"
+.B tcpserver
+starts by looking for a rule with address
+.IR TCPREMOTEINFO\fB@\fITCPREMOTEIP .
+If it doesn't find one, or if
+.I TCPREMOTEINFO
+is not set, it tries the address
+.IR TCPREMOTEIP .
+If that doesn't work, it tries shorter and shorter prefixes of
+.I TCPREMOTEIP
+ending with a dot.
+If none of them work, it tries the empty string.
+
+For example, here are some rules:
+
+.EX
+ joe@127.0.0.1:first
+.br
+ 18.23.0.32:second
+.br
+ 127.:third
+.br
+ :fourth
+.EE
+
+If
+.I TCPREMOTEIP
+is
+.BR 10.119.75.38 ,
+.B tcpserver
+will follow the
+.B fourth
+instructions.
+
+If
+.I TCPREMOTEIP
+is
+.BR 18.23.0.32 ,
+.B tcpserver
+will follow the
+.B second
+instructions.
+
+If
+.I TCPREMOTEINFO
+is
+.B bill
+and
+.I TCPREMOTEIP
+is
+.BR 127.0.0.1 ,
+.B tcpserver
+will follow the
+.B third
+instructions.
+
+If
+.I TCPREMOTEINFO
+is
+.B joe
+and
+.I TCPREMOTEIP
+is
+.BR 127.0.0.1 ,
+.B tcpserver
+will follow the
+.B first
+instructions.
+.SH "ADDRESS RANGES"
+.B tcprules
+treats
+.B 1.2.3.37-53:ins
+as an abbreviation
+for the rules
+.BR 1.2.3.37:ins ,
+.BR 1.2.3.38:ins ,
+and so on up through
+.BR 1.2.3.53:ins .
+Similarly,
+.BR 10.2-3.:ins
+is an abbreviation for
+.B 10.2.:ins
+and
+.BR 10.3.:ins .
+.SH "INSTRUCTIONS"
+The instructions in a rule must begin with either
+.B allow
+or
+.BR deny .
+.B deny
+tells
+.B tcpserver
+to drop the connection without running anything.
+For example, the rule
+
+.EX
+ :deny
+.EE
+
+tells
+.B tcpserver
+to drop all connections that aren't handled by more specific rules.
+
+The instructions may continue with some environment variables,
+in the format
+.IR ,VAR="VALUE" .
+.B tcpserver
+adds
+.I VAR=VALUE
+to the current environment.
+For example,
+
+.EX
+ 10.0.:allow,RELAYCLIENT="@fix.me"
+.EE
+
+adds
+.B RELAYCLIENT=@fix.me
+to the environment.
+The quotes here may be replaced by any repeated character:
+
+.EX
+ 10.0.:allow,RELAYCLIENT=/@fix.me/
+.EE
+
+Any number of variables may be listed:
+
+.EX
+ 127.0.0.1:allow,RELAYCLIENT="",TCPLOCALHOST="movie.edu"
+.EE
+.SH "SEE ALSO"
+tcpserver(1),
+tcp-environ(5)
diff --git a/tcprules.c b/tcprules.c
new file mode 100644
index 0000000..1264fea
--- /dev/null
+++ b/tcprules.c
@@ -0,0 +1,177 @@
+#include "strerr.h"
+#include "stralloc.h"
+#include "getln.h"
+#include "substdio.h"
+#include "subfd.h"
+#include "exit.h"
+#include "fmt.h"
+#include "byte.h"
+#include "cdbmss.h"
+
+#define FATAL "tcprules: fatal: "
+
+unsigned long linenum = 0;
+char *fntemp;
+char *fn;
+
+stralloc line = {0};
+int match = 1;
+
+stralloc address = {0};
+stralloc data = {0};
+stralloc key = {0};
+
+struct cdbmss cdbmss;
+
+void die_nomem() {
+ strerr_die2x(111,FATAL,"out of memory");
+}
+void usage() {
+ strerr_die1x(100,"tcprules: usage: tcprules rules.cdb rules.tmp");
+}
+void die_bad() {
+ if (!stralloc_0(&line)) die_nomem();
+ strerr_die3x(100,FATAL,"unable to parse this line: ",line.s);
+}
+void die_write() {
+ strerr_die4sys(111,FATAL,"unable to write to ",fntemp,": ");
+}
+
+char strnum[FMT_ULONG];
+stralloc sanum = {0};
+
+void getnum(buf,len,u)
+char *buf;
+int len;
+unsigned long *u;
+{
+ if (!stralloc_copyb(&sanum,buf,len)) die_nomem();
+ if (!stralloc_0(&sanum)) die_nomem();
+ if (sanum.s[scan_ulong(sanum.s,u)]) die_bad();
+}
+
+void doaddressdata()
+{
+ int i;
+ int left;
+ int right;
+ unsigned long bot;
+ unsigned long top;
+
+ if (byte_chr(address.s,address.len,'@') == address.len) {
+ i = byte_chr(address.s,address.len,'-');
+ if (i < address.len) {
+ left = byte_rchr(address.s,i,'.');
+ if (left == i) left = 0; else ++left;
+
+ ++i;
+ right = i + byte_chr(address.s + i,address.len - i,'.');
+
+ getnum(address.s + left,i - 1 - left,&bot);
+ getnum(address.s + i,right - i,&top);
+ if (top > 255) top = 255;
+
+ while (bot <= top) {
+ if (!stralloc_copyb(&key,address.s,left)) die_nomem();
+ if (!stralloc_catb(&key,strnum,fmt_ulong(strnum,bot))) die_nomem();
+ if (!stralloc_catb(&key,address.s + right,address.len - right)) die_nomem();
+ if (cdbmss_add(&cdbmss,key.s,key.len,data.s,data.len) == -1) die_write();
+ ++bot;
+ }
+
+ return;
+ }
+ }
+
+ if (!stralloc_copy(&key,&address)) die_nomem();
+ if (cdbmss_add(&cdbmss,key.s,key.len,data.s,data.len) == -1) die_write();
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+ int colon;
+ char *x;
+ int len;
+ int fd;
+ int i;
+ char ch;
+
+ fn = argv[1];
+ if (!fn) usage();
+ fntemp = argv[2];
+ if (!fntemp) usage();
+
+ fd = open_trunc(fntemp);
+ if (fd == -1)
+ strerr_die4sys(111,FATAL,"unable to create ",fntemp,": ");
+ if (cdbmss_start(&cdbmss,fd) == -1) die_write();
+
+ while (match) {
+ if (getln(subfdin,&line,&match,'\n') == -1)
+ strerr_die2sys(111,FATAL,"unable to read input: ");
+
+ x = line.s; len = line.len;
+
+ if (!len) break;
+ if (x[0] == '#') continue;
+ if (x[0] == '\n') continue;
+
+ while (len) {
+ ch = x[len - 1];
+ if (ch != '\n') if (ch != ' ') if (ch != '\t') break;
+ --len;
+ }
+ line.len = len; /* for die_bad() */
+
+ colon = byte_chr(x,len,':');
+ if (colon == len) continue;
+
+ if (!stralloc_copyb(&address,x,colon)) die_nomem();
+ if (!stralloc_copys(&data,"")) die_nomem();
+
+ x += colon + 1; len -= colon + 1;
+
+ if ((len >= 4) && byte_equal(x,4,"deny")) {
+ if (!stralloc_catb(&data,"D",2)) die_nomem();
+ x += 4; len -= 4;
+ }
+ else if ((len >= 5) && byte_equal(x,5,"allow")) {
+ x += 5; len -= 5;
+ }
+ else
+ die_bad();
+
+ while (len)
+ switch(*x) {
+ case ',':
+ i = byte_chr(x,len,'=');
+ if (i == len) die_bad();
+ if (!stralloc_catb(&data,"+",1)) die_nomem();
+ if (!stralloc_catb(&data,x + 1,i)) die_nomem();
+ x += i + 1; len -= i + 1;
+ if (!len) die_bad();
+ ch = *x;
+ x += 1; len -= 1;
+ i = byte_chr(x,len,ch);
+ if (i == len) die_bad();
+ if (!stralloc_catb(&data,x,i)) die_nomem();
+ if (!stralloc_0(&data)) die_nomem();
+ x += i + 1; len -= i + 1;
+ break;
+ default:
+ die_bad();
+ }
+
+ doaddressdata();
+ }
+
+ if (cdbmss_finish(&cdbmss) == -1) die_write();
+ if (fsync(fd) == -1) die_write();
+ if (close(fd) == -1) die_write(); /* NFS stupidity */
+ if (rename(fntemp,fn))
+ strerr_die6sys(111,FATAL,"unable to move ",fntemp," to ",fn,": ");
+
+ _exit(0);
+}
diff --git a/tcprules=0 b/tcprules=0
new file mode 100644
index 0000000..e12053d
--- /dev/null
+++ b/tcprules=0
@@ -0,0 +1 @@
+tcprules.1
diff --git a/tcprules=x b/tcprules=x
new file mode 100644
index 0000000..b534828
--- /dev/null
+++ b/tcprules=x
@@ -0,0 +1,12 @@
+cdbmss.o
+cdbmake.a
+getln.a
+strerr.a
+stralloc.a
+substdio.a
+alloc.a
+error.a
+open.a
+seek.a
+str.a
+fs.a
diff --git a/tcpserver.1 b/tcpserver.1
new file mode 100644
index 0000000..77000d6
--- /dev/null
+++ b/tcpserver.1
@@ -0,0 +1,220 @@
+.TH tcpserver 1
+.SH NAME
+tcpserver \- accept incoming TCP connections
+.SH SYNOPSIS
+.B tcpserver
+[
+.B \-qQvdDoOpPhHrR1
+]
+[
+.B \-c\fIlimit
+]
+[
+.B \-b\fIbacklog
+]
+[
+.B \-x\fIrules.cdb
+]
+[
+.B \-g\fIgid
+]
+[
+.B \-u\fIuid
+]
+[
+.B \-l\fIlocalname
+]
+[
+.B \-t\fItimeout
+]
+.I host
+.I port
+.I program
+[
+.I arg ...
+]
+.SH DESCRIPTION
+.B tcpserver
+waits for connections from TCP clients.
+For each connection, it runs
+.I program
+with the given arguments,
+with descriptor 0 reading from the network
+and descriptor 1 writing to the network.
+
+The server's address is given by
+.I host
+and
+.IR port .
+.I host
+can be 0, allowing connections from any host;
+or a particular IP address,
+allowing connections only to that address;
+or a host name, allowing connections to the first IP address
+for that host.
+.I port
+may be a numeric port number
+or a port name.
+If
+.I port
+is 0,
+.B tcpserver
+will choose a free port.
+
+.B tcpserver
+sets up several environment variables,
+as described in
+.B tcp-environ(5).
+
+.B tcpserver
+exits when it receives SIGTERM.
+.SH "OPTIONS"
+.TP
+.B \-c\fIlimit
+Do not handle more than
+.I limit
+simultaneous connections.
+If there are
+.I limit
+simultaneous copies of
+.I program
+running, defer acceptance of a new connection
+until one copy finishes.
+.I limit
+must be a positive integer.
+Default: 40.
+.TP
+.B \-x\fIrules.cdb
+Follow the rules compiled into
+.I rules.cdb
+by
+.BR tcprules .
+These rules may specify setting environment variables
+or rejecting connections from bad sources.
+.B tcpserver
+does not read
+.I rules.cdb
+into memory;
+you can rerun
+.B tcprules
+to change
+.BR tcpserver 's
+behavior on the fly.
+.TP
+.B \-g\fIgid
+Switch group ID to
+.I gid
+after preparing to receive connections.
+.I gid
+must be a positive integer.
+.TP
+.B \-u\fIuid
+Switch user ID to
+.I uid
+after preparing to receive connections.
+.I uid
+must be a positive integer.
+.TP
+.B \-1
+After preparing to receive connections,
+print the local port number to standard output.
+.TP
+.B \-q
+Quiet.
+Do not print any messages.
+.TP
+.B \-Q
+(Default.)
+Print error messages.
+.TP
+.B \-v
+Verbose.
+Print all available messages.
+.TP
+.B \-b\fIbacklog
+Allow up to
+.I backlog
+simultaneous SYN_RECEIVEDs.
+Default: 20.
+On some systems,
+.I backlog
+is silently limited to 5.
+See
+.BR listen (2)
+for more details.
+.TP
+.B \-o
+Leave IP options alone.
+If the client is sending packets along an IP source route,
+send packets back along the same route.
+.TP
+.B \-O
+(Default.)
+Kill IP options.
+A client can still use source routing to connect and to send data,
+but packets will be sent back along the default route.
+.TP
+.B \-d
+(Default.)
+Delay sending data for a fraction of a second whenever the
+remote host is responding slowly,
+to make better use of the network.
+.TP
+.B \-D
+Never delay sending data;
+enable TCP_NODELAY.
+This is appropriate for interactive connections.
+.SH "DATA-GATHERING OPTIONS"
+.TP
+.B \-p
+Paranoid.
+After looking up the remote host name,
+look up the IP addresses for that name,
+and make sure one of them matches
+.BR TCPREMOTEIP .
+If none of them do,
+unset
+.BR TCPREMOTEHOST .
+.TP
+.B \-P
+(Default.)
+Not paranoid.
+.TP
+.B \-h
+(Default.)
+Look up the remote host name and set
+.BR TCPREMOTEHOST .
+.TP
+.B \-H
+Do not look up the remote host name.
+.TP
+.B \-l\fIlocalname
+Do not look up the local host name;
+use
+.I localname
+for
+.BR TCPLOCALHOST .
+.TP
+.B \-r
+(Default.)
+Attempt to obtain
+.B TCPREMOTEINFO
+from the remote host.
+.TP
+.B \-R
+Do not attempt to obtain
+.B TCPREMOTEINFO
+from the remote host.
+.TP
+.B \-t\fItimeout
+Give up on the
+.B TCPREMOTEINFO
+connection attempt
+after
+.I timeout
+seconds. Default: 26.
+.SH "SEE ALSO"
+tcpclient(1),
+tcprules(1),
+listen(2),
+tcp-environ(5)
diff --git a/tcpserver.c b/tcpserver.c
new file mode 100644
index 0000000..3aa6f4e
--- /dev/null
+++ b/tcpserver.c
@@ -0,0 +1,475 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "strerr.h"
+#include "substdio.h"
+#include "stralloc.h"
+#include "alloc.h"
+#include "readwrite.h"
+#include "fd.h"
+#include "sig.h"
+#include "wait.h"
+#include "ip.h"
+#include "ipalloc.h"
+#include "dns.h"
+#include "str.h"
+#include "case.h"
+#include "byte.h"
+#include "sgetopt.h"
+#include "remoteinfo.h"
+#include "exit.h"
+#include "open.h"
+#include "scan.h"
+#include "fmt.h"
+#include "env.h"
+#include "cdb.h"
+
+#define FATAL "tcpserver: fatal: "
+#define DROP "tcpserver: warning: dropping connection, "
+int verbosity = 1;
+
+void die_nomem()
+{
+ if (verbosity) strerr_warn2(FATAL,"out of memory",0);
+ _exit(111);
+}
+void drop_nomem()
+{
+ if (verbosity) strerr_warn2(DROP,"out of memory",0);
+ _exit(111);
+}
+void usage()
+{
+ if (verbosity) strerr_warn1("\
+tcpserver: usage: \
+tcpserver [ -qQvdDoOpPhHrR1 ] \
+[ -xrules.cdb ] \
+[ -bbacklog ] [ -climit ] [ -ttimeout ] [ -llocalname ] [ -ggid ] [ -uuid ] \
+host port program",0);
+ _exit(100);
+}
+
+void safeappend(sa,s)
+stralloc *sa;
+char *s;
+{
+ char ch;
+ while (ch = *s++) {
+ if (ch < 33) ch = '?';
+ if (ch > 126) ch = '?';
+ if (ch == '%') ch = '?'; /* logger stupidity */
+ if (ch == ':') ch = '?';
+ if (!stralloc_append(sa,&ch)) drop_nomem();
+ }
+}
+
+char strnum[FMT_ULONG];
+char strnum2[FMT_ULONG];
+stralloc tmp = {0};
+ipalloc ia = {0};
+
+unsigned long numchildren = 0;
+
+char tcpremoteip[IPFMT];
+char tcpremoteport[IPFMT];
+char *tcpremoteinfo;
+struct sockaddr_in saremote;
+struct ip_address ipremote;
+unsigned long portremote;
+
+char tcplocalip[IPFMT];
+char tcplocalport[IPFMT];
+struct sockaddr_in salocal;
+struct ip_address iplocal;
+unsigned long portlocal;
+
+int fdrules;
+char *fnrules = 0;
+int flagdeny = 0;
+
+void printenv()
+{
+ char *tcplocalhost;
+ char *tcpremotehost;
+
+ if (verbosity < 2) return;
+
+ tcplocalhost = env_get("TCPLOCALHOST");
+ tcpremotehost = env_get("TCPREMOTEHOST");
+
+ if (!tcplocalhost) tcplocalhost = "";
+ if (!tcpremotehost) tcpremotehost = "";
+
+ if (!stralloc_copys(&tmp,"tcpserver: ")) drop_nomem();
+ if (!stralloc_cats(&tmp,flagdeny ? "deny " : "ok ")) drop_nomem();
+ if (!stralloc_catb(&tmp,strnum,fmt_ulong(strnum,getpid()))) drop_nomem();
+ if (!stralloc_cats(&tmp," ")) drop_nomem();
+ safeappend(&tmp,tcplocalhost);
+ if (!stralloc_cats(&tmp,":")) drop_nomem();
+ safeappend(&tmp,tcplocalip);
+ if (!stralloc_cats(&tmp,":")) drop_nomem();
+ safeappend(&tmp,tcplocalport);
+ if (!stralloc_cats(&tmp," ")) drop_nomem();
+ safeappend(&tmp,tcpremotehost);
+ if (!stralloc_cats(&tmp,":")) drop_nomem();
+ safeappend(&tmp,tcpremoteip);
+ if (!stralloc_cats(&tmp,":")) drop_nomem();
+ safeappend(&tmp,tcpremoteinfo ? tcpremoteinfo : "");
+ if (!stralloc_cats(&tmp,":")) drop_nomem();
+ safeappend(&tmp,tcpremoteport);
+ if (!stralloc_0(&tmp)) drop_nomem();
+
+ strerr_warn1(tmp.s,0);
+}
+
+void printpid()
+{
+ if (verbosity < 2) return;
+ strnum[fmt_ulong(strnum,(unsigned long) getpid())] = 0;
+ strnum2[fmt_ulong(strnum2,numchildren)] = 0;
+ strerr_warn6("tcpserver: pid ",strnum," num ",strnum2," from ",tcpremoteip,0);
+}
+
+char printbuf[16];
+struct substdio print = SUBSTDIO_FDBUF(write,1,printbuf,sizeof(printbuf));
+void printlocalport()
+{
+ substdio_puts(&print,tcplocalport);
+ substdio_puts(&print,"\n");
+ substdio_flush(&print);
+}
+
+void sigterm() { _exit(0); }
+
+void sigchld()
+{
+ int wstat;
+ int pid;
+
+ while ((pid = wait_nohang(&wstat)) > 0) {
+ if (numchildren) --numchildren;
+ if (verbosity >= 2) {
+ strnum[fmt_ulong(strnum,(unsigned long) pid)] = 0;
+ strnum2[fmt_ulong(strnum2,(unsigned long) wstat)] = 0;
+ strerr_warn4("tcpserver: end ",strnum," status ",strnum2,0);
+ }
+ }
+}
+
+void drop_rules()
+{
+ if (verbosity) strerr_warn4(DROP,"unable to read ",fnrules,": ",&strerr_sys);
+ _exit(111);
+}
+
+int dorule()
+{
+ char *data;
+ uint32 dlen32;
+ unsigned int datalen;
+ unsigned int next0;
+
+ switch(cdb_seek(fdrules,tmp.s,tmp.len,&dlen32)) {
+ case -1: drop_rules();
+ case 0: return 0;
+ }
+
+ datalen = dlen32;
+ data = alloc(datalen);
+ if (!data) drop_nomem();
+ if (cdb_bread(fdrules,data,datalen) != 0) drop_rules();
+
+ while ((next0 = byte_chr(data,datalen,0)) < datalen) {
+ switch(data[0]) {
+ case 'D': flagdeny = 1; break;
+ case '+': if (!env_put(data + 1)) drop_nomem(); break;
+ }
+ data += next0 + 1; datalen -= next0 + 1;
+ }
+ return 1;
+}
+
+void rules()
+{
+ if (!fnrules) return;
+
+ fdrules = open_read(fnrules);
+ if (fdrules == -1) drop_rules();
+
+ if (tcpremoteinfo) {
+ if (!stralloc_copys(&tmp,tcpremoteinfo)) drop_nomem();
+ if (!stralloc_cats(&tmp,"@")) drop_nomem();
+ if (!stralloc_cats(&tmp,tcpremoteip)) drop_nomem();
+ if (dorule()) goto done;
+ }
+
+ if (!stralloc_copys(&tmp,tcpremoteip)) drop_nomem();
+ if (dorule()) goto done;
+ while (tmp.len > 0) {
+ if (tcpremoteip[tmp.len - 1] == '.')
+ if (dorule()) goto done;
+ --tmp.len;
+ }
+
+ dorule();
+
+ done:
+ close(fdrules);
+}
+
+int flagkillopts = 1;
+int flagdelay = 1;
+int flagremoteinfo = 1;
+int flagremotehost = 1;
+int flagparanoid = 0;
+int flag1 = 0;
+unsigned long backlog = 20;
+unsigned long timeout = 26;
+unsigned long uid = 0;
+unsigned long gid = 0;
+char *forcelocal = 0;
+unsigned long limit = 40;
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+ int s;
+ int t;
+ int dummy;
+ int opt;
+ char *hostname;
+ char *portname;
+ struct servent *se;
+ int j;
+
+ while ((opt = getopt(argc,argv,"dDvqQhHrR1x:t:u:g:l:b:c:pPoO")) != opteof)
+ switch(opt) {
+ case 'b': scan_ulong(optarg,&backlog); break;
+ case 'c': scan_ulong(optarg,&limit); break;
+ case 'x': fnrules = optarg; break;
+ case 'd': flagdelay = 1; break;
+ case 'D': flagdelay = 0; break;
+ case 'v': verbosity = 2; break;
+ case 'q': verbosity = 0; break;
+ case 'Q': verbosity = 1; break;
+ case 'P': flagparanoid = 0; break;
+ case 'p': flagparanoid = 1; break;
+ case 'O': flagkillopts = 1; break;
+ case 'o': flagkillopts = 0; break;
+ case 'H': flagremotehost = 0; break;
+ case 'h': flagremotehost = 1; break;
+ case 'R': flagremoteinfo = 0; break;
+ case 'r': flagremoteinfo = 1; break;
+ case 't': scan_ulong(optarg,&timeout); break;
+ case 'g': scan_ulong(optarg,&gid); break;
+ case 'u': scan_ulong(optarg,&uid); break;
+ case '1': flag1 = 1; break;
+ case 'l': forcelocal = optarg; break;
+ default: usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ hostname = *argv++;
+ if (!hostname) usage();
+ portname = *argv++;
+ if (!portname) usage();
+ if (!*argv) usage();
+
+ sig_pipeignore();
+ sig_termcatch(sigterm);
+ sig_childcatch(sigchld);
+
+ dns_init(1);
+
+ byte_zero(&salocal,sizeof(salocal));
+ salocal.sin_family = AF_INET;
+
+ if (!portname[scan_ulong(portname,&portlocal)])
+ salocal.sin_port = htons((unsigned short) portlocal);
+ else {
+ se = getservbyname(portname,"tcp");
+ if (!se) {
+ if (verbosity) strerr_warn3(FATAL,"unable to figure out number for port ",portname,0);
+ _exit(111);
+ }
+ salocal.sin_port = se->s_port;
+ }
+
+ if (str_equal(hostname,"")) hostname = "0.0.0.0";
+ if (str_equal(hostname,"0")) hostname = "0.0.0.0";
+
+ if (hostname[ip_scan(hostname,&iplocal)]) {
+ if (!stralloc_copys(&tmp,hostname)) die_nomem();
+ switch(dns_ip(&ia,&tmp)) {
+ case DNS_MEM:
+ die_nomem();
+ case DNS_HARD:
+ if (verbosity) strerr_warn3(FATAL,"unable to figure out address for host ",hostname,0);
+ _exit(111);
+ case DNS_SOFT:
+ if (verbosity) strerr_warn3(FATAL,"temporarily unable to figure out address for host ",hostname,0);
+ _exit(111);
+ }
+ if (!ia.len) {
+ if (verbosity) strerr_warn3(FATAL,"no IP addresses for host ",hostname,0);
+ _exit(111);
+ }
+ byte_copy(&iplocal,4,&ia.ix[0].ip);
+ }
+
+ byte_copy(&salocal.sin_addr,4,&iplocal);
+ s = socket(AF_INET,SOCK_STREAM,0);
+ if (s == -1) {
+ if (verbosity) strerr_warn2(FATAL,"unable to create socket: ",&strerr_sys);
+ _exit(111);
+ }
+
+ {
+ int opt = 1;
+ setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
+ }
+
+ if (bind(s,(struct sockaddr *) &salocal,sizeof(salocal)) == -1) {
+ if (verbosity) strerr_warn2(FATAL,"unable to bind: ",&strerr_sys);
+ _exit(111);
+ }
+ dummy = sizeof(salocal);
+ if (getsockname(s,(struct sockaddr *) &salocal,&dummy) == -1) {
+ if (verbosity) strerr_warn2(FATAL,"unable to get local address: ",&strerr_sys);
+ _exit(111);
+ }
+ if (listen(s,backlog) == -1) {
+ if (verbosity) strerr_warn2(FATAL,"unable to listen: ",&strerr_sys);
+ _exit(111);
+ }
+
+ if (gid) if (setgid(gid) == -1) {
+ if (verbosity) strerr_warn2(FATAL,"unable to set gid: ",&strerr_sys);
+ _exit(100);
+ }
+ if (uid) if (setuid(uid) == -1) {
+ if (verbosity) strerr_warn2(FATAL,"unable to set uid: ",&strerr_sys);
+ _exit(100);
+ }
+
+ if (!env_init()) die_nomem();
+ if (!env_put("PROTO=TCP")) die_nomem();
+ if (!env_unset("TCPLOCALHOST")) die_nomem();
+ if (!env_unset("TCPREMOTEHOST")) die_nomem();
+ if (!env_unset("TCPREMOTEINFO")) die_nomem();
+
+ if (forcelocal)
+ if (!env_put2("TCPLOCALHOST",forcelocal)) die_nomem();
+
+ portlocal = ntohs(salocal.sin_port);
+ tcplocalport[fmt_ulong(tcplocalport,portlocal)] = 0;
+ if (!env_put2("TCPLOCALPORT",tcplocalport)) die_nomem();
+ if (flag1) printlocalport();
+
+ close(0);
+ close(1);
+ sig_childblock();
+
+ for (;;) {
+ while (numchildren >= limit) sig_pause();
+ sig_childunblock();
+
+ dummy = sizeof(saremote);
+ t = accept(s,(struct sockaddr *) &saremote,&dummy);
+ if (t == -1) continue;
+ portremote = ntohs(saremote.sin_port);
+ byte_copy(&ipremote,4,&saremote.sin_addr);
+
+ sig_childblock();
+
+ switch(fork()) {
+ default:
+ ++numchildren;
+ break;
+ case -1:
+ if (verbosity) strerr_warn2(DROP,"unable to fork: ",&strerr_sys);
+ break;
+ case 0:
+ tcpremoteip[ip_fmt(tcpremoteip,&ipremote)] = 0;
+ printpid();
+
+ close(s);
+ if (flagkillopts) {
+ setsockopt(t,IPPROTO_IP,1,(char *) 0,0); /* 1 == IP_OPTIONS */
+ /* if it fails, bummer */
+ }
+ if (!flagdelay) {
+ int opt = 1;
+ setsockopt(t,IPPROTO_TCP,1,&opt,sizeof(opt)); /* 1 == TCP_NODELAY */
+ /* if it fails, bummer */
+ }
+
+ dummy = sizeof(salocal);
+ if (getsockname(t,(struct sockaddr *) &salocal,&dummy) == -1) {
+ if (verbosity) strerr_warn2(DROP,"unable to get local address",&strerr_sys);
+ _exit(111);
+ }
+ byte_copy(&iplocal,4,&salocal.sin_addr);
+
+ tcplocalip[ip_fmt(tcplocalip,&iplocal)] = 0;
+ tcpremoteport[fmt_ulong(tcpremoteport,portremote)] = 0;
+
+ if (!env_put2("TCPREMOTEIP",tcpremoteip)) drop_nomem();
+ if (!env_put2("TCPLOCALIP",tcplocalip)) drop_nomem();
+ if (!env_put2("TCPREMOTEPORT",tcpremoteport)) drop_nomem();
+
+ if (!forcelocal)
+ switch(dns_ptr(&tmp,&iplocal)) {
+ case DNS_MEM: drop_nomem();
+ case 0:
+ if (!stralloc_0(&tmp)) drop_nomem();
+ case_lowers(tmp.s);
+ if (!env_put2("TCPLOCALHOST",tmp.s)) drop_nomem();
+ }
+
+ if (flagremotehost)
+ switch(dns_ptr(&tmp,&ipremote)) {
+ case DNS_MEM: drop_nomem();
+ case 0:
+ if (flagparanoid) {
+ if (dns_ip(&ia,&tmp) != 0) break;
+ for (j = 0;j < ia.len;++j)
+ if (!byte_diff(&ipremote,4,&ia.ix[j].ip))
+ break;
+ if (j == ia.len)
+ break;
+ }
+ if (!stralloc_0(&tmp)) drop_nomem();
+ case_lowers(tmp.s);
+ if (!env_put2("TCPREMOTEHOST",tmp.s)) drop_nomem();
+ }
+ if (flagremoteinfo) {
+ tcpremoteinfo = remoteinfo_get(&ipremote,portremote,&iplocal,portlocal,(int) timeout);
+ if (tcpremoteinfo)
+ if (!env_put2("TCPREMOTEINFO",tcpremoteinfo)) drop_nomem();
+ }
+
+ rules();
+ printenv();
+ if (flagdeny) _exit(100);
+
+ if ((fd_move(0,t) == -1) || (fd_copy(1,0) == -1)) {
+ if (verbosity) strerr_warn2(DROP,"unable to set up descriptors: ",&strerr_sys);
+ _exit(111);
+ }
+ sig_childunblock();
+ sig_childdefault();
+ sig_termdefault();
+ sig_pipedefault();
+ execvp(*argv,argv);
+ if (verbosity) strerr_warn4(DROP,"unable to run ",*argv,": ",&strerr_sys);
+ _exit(111);
+ }
+ close(t);
+ }
+}
diff --git a/tcpserver=0 b/tcpserver=0
new file mode 100644
index 0000000..6dc8469
--- /dev/null
+++ b/tcpserver=0
@@ -0,0 +1 @@
+tcpserver.1
diff --git a/tcpserver=x b/tcpserver=x
new file mode 100644
index 0000000..c1eaae9
--- /dev/null
+++ b/tcpserver=x
@@ -0,0 +1,25 @@
+ip.o
+ipalloc.o
+dns.o
+remoteinfo.o
+timeoutconn.o
+timeoutread.o
+timeoutwrite.o
+cdb.a
+open.a
+wait.a
+strerr.a
+stralloc.a
+env.a
+ndelay.a
+alloc.a
+getopt.a
+substdio.a
+error.a
+str.a
+sig.a
+fd.a
+case.a
+fs.a
+dns.lib
+socket.lib
diff --git a/timeoutconn.c b/timeoutconn.c
new file mode 100644
index 0000000..33a16d9
--- /dev/null
+++ b/timeoutconn.c
@@ -0,0 +1,59 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "ndelay.h"
+#include "select.h"
+#include "error.h"
+#include "readwrite.h"
+#include "ip.h"
+#include "byte.h"
+#include "timeoutconn.h"
+
+int timeoutconn(s,ip,port,timeout)
+int s;
+struct ip_address *ip;
+unsigned int port;
+int timeout;
+{
+ char ch;
+ struct sockaddr_in sin;
+ char *x;
+ fd_set wfds;
+ struct timeval tv;
+
+ byte_zero(&sin,sizeof(sin));
+ byte_copy(&sin.sin_addr,4,ip);
+ x = (char *) &sin.sin_port;
+ x[1] = port; port >>= 8; x[0] = port;
+ sin.sin_family = AF_INET;
+
+ if (ndelay_on(s) == -1) return -1;
+
+ /* XXX: could bind s */
+
+ if (connect(s,(struct sockaddr *) &sin,sizeof(sin)) == 0) {
+ ndelay_off(s);
+ return 0;
+ }
+ if ((errno != error_inprogress) && (errno != error_wouldblock)) return -1;
+
+ FD_ZERO(&wfds);
+ FD_SET(s,&wfds);
+ tv.tv_sec = timeout; tv.tv_usec = 0;
+
+ if (select(s + 1,(fd_set *) 0,&wfds,(fd_set *) 0,&tv) == -1) return -1;
+ if (FD_ISSET(s,&wfds)) {
+ int dummy;
+ dummy = sizeof(sin);
+ if (getpeername(s,(struct sockaddr *) &sin,&dummy) == -1) {
+ read(s,&ch,1);
+ return -1;
+ }
+ ndelay_off(s);
+ return 0;
+ }
+
+ errno = error_timeout; /* note that connect attempt is continuing */
+ return -1;
+}
diff --git a/timeoutconn.h b/timeoutconn.h
new file mode 100644
index 0000000..88aab06
--- /dev/null
+++ b/timeoutconn.h
@@ -0,0 +1,6 @@
+#ifndef TIMEOUTCONN_H
+#define TIMEOUTCONN_H
+
+extern int timeoutconn();
+
+#endif
diff --git a/timeoutread.c b/timeoutread.c
new file mode 100644
index 0000000..c75e29c
--- /dev/null
+++ b/timeoutread.c
@@ -0,0 +1,22 @@
+#include "timeoutread.h"
+#include "select.h"
+#include "error.h"
+#include "readwrite.h"
+
+int timeoutread(t,fd,buf,len) int t; int fd; char *buf; int len;
+{
+ fd_set rfds;
+ struct timeval tv;
+
+ tv.tv_sec = t;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&rfds);
+ FD_SET(fd,&rfds);
+
+ if (select(fd + 1,&rfds,(fd_set *) 0,(fd_set *) 0,&tv) == -1) return -1;
+ if (FD_ISSET(fd,&rfds)) return read(fd,buf,len);
+
+ errno = error_timeout;
+ return -1;
+}
diff --git a/timeoutread.h b/timeoutread.h
new file mode 100644
index 0000000..20d3bfc
--- /dev/null
+++ b/timeoutread.h
@@ -0,0 +1,6 @@
+#ifndef TIMEOUTREAD_H
+#define TIMEOUTREAD_H
+
+extern int timeoutread();
+
+#endif
diff --git a/timeoutwrite.c b/timeoutwrite.c
new file mode 100644
index 0000000..516d283
--- /dev/null
+++ b/timeoutwrite.c
@@ -0,0 +1,22 @@
+#include "timeoutwrite.h"
+#include "select.h"
+#include "error.h"
+#include "readwrite.h"
+
+int timeoutwrite(t,fd,buf,len) int t; int fd; char *buf; int len;
+{
+ fd_set wfds;
+ struct timeval tv;
+
+ tv.tv_sec = t;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&wfds);
+ FD_SET(fd,&wfds);
+
+ if (select(fd + 1,(fd_set *) 0,&wfds,(fd_set *) 0,&tv) == -1) return -1;
+ if (FD_ISSET(fd,&wfds)) return write(fd,buf,len);
+
+ errno = error_timeout;
+ return -1;
+}
diff --git a/timeoutwrite.h b/timeoutwrite.h
new file mode 100644
index 0000000..4725861
--- /dev/null
+++ b/timeoutwrite.h
@@ -0,0 +1,6 @@
+#ifndef TIMEOUTWRITE_H
+#define TIMEOUTWRITE_H
+
+extern int timeoutwrite();
+
+#endif
diff --git a/trycpp.c b/trycpp.c
new file mode 100644
index 0000000..d7d83ad
--- /dev/null
+++ b/trycpp.c
@@ -0,0 +1,7 @@
+void main()
+{
+#ifdef NeXT
+ printf("nextstep\n"); exit(0);
+#endif
+ printf("unknown\n"); exit(0);
+}
diff --git a/trylsock.c b/trylsock.c
new file mode 100644
index 0000000..fbce408
--- /dev/null
+++ b/trylsock.c
@@ -0,0 +1,4 @@
+main()
+{
+ ;
+}
diff --git a/tryrsolv.c b/tryrsolv.c
new file mode 100644
index 0000000..fbce408
--- /dev/null
+++ b/tryrsolv.c
@@ -0,0 +1,4 @@
+main()
+{
+ ;
+}
diff --git a/trysgact.c b/trysgact.c
new file mode 100644
index 0000000..263cb21
--- /dev/null
+++ b/trysgact.c
@@ -0,0 +1,10 @@
+#include <signal.h>
+
+void main()
+{
+ struct sigaction sa;
+ sa.sa_handler = 0;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(0,&sa,(struct sigaction *) 0);
+}
diff --git a/trysgprm.c b/trysgprm.c
new file mode 100644
index 0000000..ed28857
--- /dev/null
+++ b/trysgprm.c
@@ -0,0 +1,10 @@
+#include <signal.h>
+
+void main()
+{
+ sigset_t ss;
+
+ sigemptyset(&ss);
+ sigaddset(&ss,SIGCHLD);
+ sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0);
+}
diff --git a/trysysel.c b/trysysel.c
new file mode 100644
index 0000000..f6ed055
--- /dev/null
+++ b/trysysel.c
@@ -0,0 +1,8 @@
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/select.h> /* SVR4 silliness */
+
+void foo()
+{
+ ;
+}
diff --git a/tryulong32.c b/tryulong32.c
new file mode 100644
index 0000000..a108076
--- /dev/null
+++ b/tryulong32.c
@@ -0,0 +1,11 @@
+void main()
+{
+ unsigned long u;
+ u = 1;
+ u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u;
+ u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u;
+ u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u;
+ u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u;
+ if (!u) _exit(0);
+ _exit(1);
+}
diff --git a/trywaitp.c b/trywaitp.c
new file mode 100644
index 0000000..7e73bfa
--- /dev/null
+++ b/trywaitp.c
@@ -0,0 +1,7 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void main()
+{
+ waitpid(0,0,0);
+}
diff --git a/uint32.h.do b/uint32.h.do
new file mode 100644
index 0000000..b87401d
--- /dev/null
+++ b/uint32.h.do
@@ -0,0 +1,7 @@
+dependon tryulong32.c compile load uint32.h1 uint32.h2
+( ./compile tryulong32.c && ./load tryulong32 && ./tryulong32 ) >/dev/null 2>&1 \
+&& cat uint32.h2 || cat uint32.h1
+rm -f tryulong32.o tryulong32
+formake '( ( ./compile tryulong32.c && ./load tryulong32 && ./tryulong32 ) >/dev/null 2>&1 \'
+formake '&& cat uint32.h2 || cat uint32.h1 ) > uint32.h'
+formake 'rm -f tryulong32.o tryulong32'
diff --git a/uint32.h1 b/uint32.h1
new file mode 100644
index 0000000..6599aa0
--- /dev/null
+++ b/uint32.h1
@@ -0,0 +1,6 @@
+#ifndef UINT32_H
+#define UINT32_H
+
+typedef unsigned int uint32;
+
+#endif
diff --git a/uint32.h2 b/uint32.h2
new file mode 100644
index 0000000..716430d
--- /dev/null
+++ b/uint32.h2
@@ -0,0 +1,6 @@
+#ifndef UINT32_H
+#define UINT32_H
+
+typedef unsigned long uint32;
+
+#endif
diff --git a/wait.h b/wait.h
new file mode 100644
index 0000000..cdb77c3
--- /dev/null
+++ b/wait.h
@@ -0,0 +1,14 @@
+#ifndef WAIT_H
+#define WAIT_H
+
+extern int wait_pid();
+extern int wait_nohang();
+extern int wait_stop();
+extern int wait_stopnohang();
+
+#define wait_crashed(w) ((w) & 127)
+#define wait_exitcode(w) ((w) >> 8)
+#define wait_stopsig(w) ((w) >> 8)
+#define wait_stopped(w) (((w) & 127) == 127)
+
+#endif
diff --git a/wait=l b/wait=l
new file mode 100644
index 0000000..1ebab98
--- /dev/null
+++ b/wait=l
@@ -0,0 +1 @@
+wait_nohang.o
diff --git a/wait_nohang.c b/wait_nohang.c
new file mode 100644
index 0000000..bea2774
--- /dev/null
+++ b/wait_nohang.c
@@ -0,0 +1,12 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "haswaitp.h"
+
+int wait_nohang(wstat) int *wstat;
+{
+#ifdef HASWAITPID
+ return waitpid(-1,wstat,WNOHANG);
+#else
+ return wait3(wstat,WNOHANG,(struct rusage *) 0);
+#endif
+}
diff --git a/warn-auto.sh b/warn-auto.sh
new file mode 100644
index 0000000..36d2313
--- /dev/null
+++ b/warn-auto.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+# WARNING: This file was auto-generated. Do not edit!
diff --git a/who@.sh b/who@.sh
new file mode 100644
index 0000000..b4ee553
--- /dev/null
+++ b/who@.sh
@@ -0,0 +1 @@
+BIN/tcpclient -RHl0 -- "${1-0}" 11 sh -c 'exec BIN/delcr <&6' | cat -v
diff --git a/who@=s b/who@=s
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/who@=s