debian/0000755000000000000000000000000012156343141007166 5ustar debian/source/0000775000000000000000000000000011751166627010504 5ustar debian/source/format0000644000000000000000000000001411751166627011710 0ustar 3.0 (quilt) debian/examples0000644000000000000000000000005311751166627010741 0ustar sample/* debian/get-news.conf debian/ip-up debian/get-news.conf0000644000000000000000000000363211751166627011606 0ustar # Debian GNU/Linux suck package /usr/sbin/get-news config file # Your default local NNTP server. # (inn1 note: must be in /etc/news/hosts.nntp) # (inn2 note: must be in /etc/news/incoming.conf) server: localhost # the type of the local server # servtype inn2 may only work if your inn2 version matches # the version suck was compiled with. # servtype other may need to set rnews # servtype: cnews # servtype: inn1 # servtype: inn2.3 # servtype: other # servtype: inn2 # The default NNTP server you will connect to. Suck will use # the defaults files sucknewsrc, suckkillfile and suckothermsgs # for this default remote server. remoteserver: news.example.com # The default outgoing articles file for your default remote server. # (inn1 & inn2 note: see /etc/news/newsfeeds) # outgoingfile: news.example.com # The sed command used for outgoing articles. sedcmd: /^NNTP-Posting-Host:\|^NNTP-Posting-Date:\|^X-Complaints-To:\|^Xref:\|^X-Trace:\|^X-Server-Date:/d # The userid to send to the remote server. #userid: # This is a per-site username, not a global one, unlike the one above #news.example.com_userid: foo # The password to send to the remote server. #password: # This is a per-site password, not a global one unlike the one above. #news.example.com_password: bar # The remote server port number if not standard. #remoteport: # The list of suck options if desired. suckoptions: -q -n # The list of rpost options if desired. # rpostoptions: # Per site options. Those override the normal ones. # news.example.com_suckoptions: # news.example.com_rpostoptions: # news.example.com_remoteport # some things you probably won't need to change from the defaults # batchmode: -br # rnews: /usr/lib/news/input/rnews # rnews: /usr/bin/rnews # bindir: /usr/bin # etcdir: /etc/suck # logdir: /var/log/suck # process: gp # quiet: 0 # remoteport: 119 # spooldir: /var/spool/suck # statedir: /var/lib/suck # timestamp: 0 # verbose: 0 debian/patches/0000755000000000000000000000000012150347662010623 5ustar debian/patches/02_manpages.diff0000664000000000000000000000070612150346721013551 0ustar --- a/man/rpost.1 +++ b/man/rpost.1 @@ -93,7 +93,7 @@ variable .BI NNTPSERVER. The hostname may optionally include the port number, in the form .BI Host:Port -. If this form is used, any port number specified via the -N option +If this form is used, any port number specified via the -N option will be ignored. .SH Generic Options --- a/man/suck.1 +++ b/man/suck.1 @@ -21,7 +21,7 @@ hostname .BI \-L[SL] ] [ -.Bi \-LF +.BI \-LF filename ] [ debian/patches/series0000644000000000000000000000013312150346765012040 0ustar 01_rpost-ssl.diff 02_manpages.diff 03_IPv6.diff 04_suck_confif.diff debian-changes-4.3.2-7 debian/patches/01_rpost-ssl.diff0000664000000000000000000000070712150346714013726 0ustar --- a/Makefile.in +++ b/Makefile.in @@ -217,7 +217,7 @@ xover.o: xover.c $(CC) -c $(CFLAGS) $(DBZ_GCC_FLAGS) $(CPPFLAGS) $(DEFS) $(PERL_DEFS) $(PERL_INC_LOC) $< rpost.o: rpost.c - $(CC) -c $(CFLAGS) $(DBZ_GCC_FLAGS) $(CPPFLAGS) $(DEFS) $(PERL_DEFS) $(PERL_INC_LOC) $< + $(CC) -c $(CFLAGS) $(SSL_DEFS) $(DBZ_GCC_FLAGS) $(CPPFLAGS) $(DEFS) $(PERL_DEFS) $(PERL_INC_LOC) $< .c.o: $(CC) -c $(CFLAGS) $(SSL_DEFS) $(GCC_FLAGS) $(CPPFLAGS) $(DEFS) $< debian/patches/debian-changes-4.3.2-70000644000000000000000000030574311751166627014226 0ustar Description: Upstream changes introduced in version 4.3.2-7 This patch has been created by dpkg-source during the package build. Here's the last changelog entry, hopefully it gives details on why those changes were made: . suck (4.3.2-7) unstable; urgency=low . * debian/control add quilt in Build-depedns. New patch 01_rpost-ssl to add ssl support to rpost (Closes: #501343). * Added libperl-dev in Build-depends. * Fix typo in get-news rpostopts --> rpostoptions (Closes: #605272). * Fix read file configuration with number (Closes: #410372). . The person named in the Author field signed this changelog entry. Author: Christian Marillat Bug-Debian: http://bugs.debian.org/410372 Bug-Debian: http://bugs.debian.org/501343 Bug-Debian: http://bugs.debian.org/605272 --- The information above should follow the Patch Tagging Guidelines, please checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here are templates for supplementary fields that you might want to add: Origin: , Bug: Bug-Debian: http://bugs.debian.org/ Bug-Ubuntu: https://launchpad.net/bugs/ Forwarded: Reviewed-By: Last-Update: --- /dev/null +++ suck-4.3.2/chkhistory_multi.c @@ -0,0 +1,33 @@ +/* Select chistory version at runtime rather than compile time. + * ckkhistory_cnews and chkhistory_inn are alternate compilations of + * chkhistory_db.c + */ + +#include +#include "suck_config.h" +#include "suck.h" +#include "both.h" + +void chhistory_other(PMaster master); +void chhistory_cnews(PMaster master); +void chhistory_inn(PMaster master); + +void chkhistory(PMaster master) { + if(master->debug == TRUE) { + do_debug("chkhistory_multi: %d\n", master->history_type); + do_debug("history_file: %s\n", master->history_file); + } + switch(master->history_type) { + case HIST_NONE: + break; + case HIST_OTHER: + chkhistory_other(master); + break; + case HIST_CNEWS: + chkhistory_cnews(master); + break; + case HIST_INN: + chkhistory_inn(master); + break; + } +} --- /dev/null +++ suck-4.3.2/cndbz.h @@ -0,0 +1,19 @@ +/* hack by Blars to allow linking both inn2 and cnews routines */ +/* This redefines the cnews dbz routines not to conflict with libinn */ + +#define dbzagain cn_dbzagain +#define dbzcancel cn_dbzcancel +#define dbzdbmclose cn_dbzdbmclose +#define dbzdbmfetch cn_dbzdbmfetch +#define dbzdbminit cn_dbzdbminit +#define dbzdbmstore cn_dbzdbmstore +#define dbzdebug cn_dbzdebug +#define dbzfetch cn_dbzfetch +#define dbzfiledesc cn_dbzfiledesc +#define dbzfresh cn_dbzfresh +#define dbzincore cn_dbzincore +#define dbzsize cn_dbzsize +#define dbzstore cn_dbzstore +#define dbzsync cn_dbzsync +#define dbztagmask cn_dbztagmask +#define dbzwritethrough cn_dbzwritethrough --- /dev/null +++ suck-4.3.2/libdbz/dbz.h @@ -0,0 +1,39 @@ +/* for dbm and dbz */ +typedef struct { + char *dptr; + int dsize; +} datum; + +/* standard dbm functions */ +extern int dbminit(); +extern datum fetch(); +extern int store(); +extern int delete(); /* not in dbz */ +extern datum firstkey(); /* not in dbz */ +extern datum nextkey(); /* not in dbz */ +extern int dbmclose(); /* in dbz, but not in old dbm */ + +/* new stuff for dbz */ +extern int dbzdbminit(); +extern datum dbzdbmfetch(); +extern int dbzdbmstore(); +extern int dbzdbmclose(); +extern int dbzfresh(); +extern int dbzagain(); +extern datum dbzfetch(); +extern int dbzstore(); +extern int dbzsync(); +extern long dbzsize(); +extern long dbztagmask(); +extern int dbzincore(); +extern int dbzwritethrough(); +extern void (*dbzfiledesc())(); +extern int dbzcancel(); +extern int dbzdebug(); + +/* + * In principle we could handle unlimited-length keys by operating a chunk + * at a time, but it's not worth it in practice. Setting a nice large + * bound on them simplifies the code and doesn't hurt anything. + */ +#define DBZMAXKEY 255 --- /dev/null +++ suck-4.3.2/libdbz/makefile @@ -0,0 +1,226 @@ +# cnews dbz makefile hacked by Blars for use with suck: +# remove dbzdbm +# don't use ../conf or ../include + +# =()<@@>()= +# .include "../include/config.make" +# make header file +# pathname variables +# =()@>()= +NEWSARTS=/var/spool/news +# =()@>()= +NEWSOV=/var/spool/news +# =()@>()= +NEWSBIN=/usr/lib/news +# =()@>()= +NEWSCTL=/var/lib/news +# =()@>()= +NEWSCONFIG=/usr/lib/news/config + +# workaround for System V make bug +SHELL=/bin/sh + +# directories where things go +UIBIN=/usr/lib/news +RBIN=/usr/lib/news/input + +# compilation stuff +# LIB is for makefile dependencies, LIBS for cc invocations +LIB=../libcnews.a +LIBS=../libcnews.a +MCFLAGS=$(MORECFLAGS) -O2 -DFASTSTRCHR -I. +LDFLAGS=$(CFLAGS) -s +LINTFLAGS=$(MORELINTFLAGS) -I. + +# directories etc. +MAKE=make +TO=$(CONF)/cpto +IN=$(CONF)/cmpto $(CMPOPT) +CF=$(CONF)/checkfile $(CMPOPT) +MKDIR=$(CONF)/mkdirs +MX=chmod +x +# ++roman: no need for ranlib on Linux, ar s does it; and use $(AR) for +# cross compiling +AR=ar +#UPDATE=$(CONF)/update.ran ../libcnews.a +UPDATE=$(AR) rusv ../libcnews.a +LIBCMP=$(CONF)/libcmp ../libcnews.a + +# misc configuration bits +SPACEFOR=statfs +DOSPACEFOR=dospacefor +QUEUELEN=tay +UID=news +GID=news +SIZE=big +DBZ=libdbz +STDIO=sysstdio +SERVER= +REPORTTO=newsmaster +URGENTTO=newscrisis + +# fake files needed +HFAKE= sys/timeb.h +OFAKE= fgetline.o fsync.o + +RFC=-DHAVERFCIZE +DEBUG=-DDBZDEBUG + +# database sizes for performance tests, regression, and regression prime-find +TSIZE=12007 +RSIZE=4019 +RPSIZE=2679 + +# history files for regression and performance tests +RHIST=hist3.3 +R2HIST=hist10 +THIST=hist13 + +OBJS=dbz.o +ALL=$(OBJS) + +u: $(ALL) + $(UPDATE) $(OBJS) + +o: $(OBJS) + +# the following is made explicit to simplify modifications on systems (mostly +# x86 System Vs) where -O fouls up dbz.o somehow +dbz.o: dbz.c ../cndbz.h + $(CC) $(CFLAGS) $(MCFLAGS) -include "../cndbz.h" -c dbz.c + +t: tdbz fake + +lint: + lint $(LINTFLAGS) dbzmain.c dbz.c + +rdbz tdbz fake byteflip: $(LIB) + +rdbz.o: dbz.c + cp dbz.c rdbz.c + $(CC) $(CFLAGS) $(DEBUG) -DDEFSIZE=$(RSIZE) -c rdbz.c + rm -f rdbz.c + +rdbzmain.o: dbzmain.c + cp dbzmain.c rdbzmain.c + $(CC) $(CFLAGS) $(RFC) -c rdbzmain.c + rm -f rdbzmain.c + +tdbz.o: dbz.c + cp dbz.c tdbz.c + $(CC) $(CFLAGS) -DDEFSIZE=$(TSIZE) -c tdbz.c + rm -f tdbz.c + +tdbz: dbzmain.o tdbz.o dbzdbm.o + $(CC) $(LDFLAGS) dbzmain.o tdbz.o dbzdbm.o $(LIBS) -o $@ + +rdbz: rdbzmain.o rdbz.o dbzdbm.o + $(CC) $(LDFLAGS) rdbzmain.o rdbz.o dbzdbm.o $(LIBS) -o $@ + +fake: fake.o random.o + $(CC) $(LDFLAGS) fake.o random.o $(LIBS) -o $@ + +byteflip: byteflip.o + $(CC) $(LDFLAGS) byteflip.o $(LIBS) -o $@ + +hist10: fake + ./fake -t -e 75 10000 >$@ + +hist3.3: fake + ./fake -t -e 75 3300 >$@ + +hist13: fake + ./fake -t -e 75 13000 >$@ + +r: rclean rdbz $(RHIST) $(R2HIST) byteflip getmap revbytes altbytes + : 'WARNING: creates about 2MB of debris...' + : crude check of synthetic history file + ( sed 25q $(RHIST) ; tail -25 $(RHIST) ) >histjunk + cmp histjunk firstlast25 + rm -f histjunk + : basic tests, exercising as many options as possible + cp $(RHIST) dbase + mkdir xx + chmod -w xx + ./rdbz -E 1000 -0 -M -i -S -u -U -C xx dbase + rmdir xx + sed '/> 0/d' $(RHIST) >dbase.used + test "`cat dbase.used | wc -l`" -eq "`sed -n '2s/ .*//p' dbase.dir`" ; + ./rdbz -v dbase + cp $(RHIST) dbase2 + ./rdbz -E 1000 -0 -p $(RPSIZE) -t ' ' dbase2 + cmp $(RHIST) dbase + cmp dbase dbase2 + cmp dbase.dir dbase2.dir + cmp dbase.pag dbase2.pag + ./rdbz -E 1000 -0 -c dbase + ./rdbz -E 1000 -0 -c -i -q -M -U dbase + : build a database and then add to it + sed 1000q $(RHIST) >dbase2 + sed 1,1000d $(RHIST) >dbase2.add + ./rdbz -E 1000 -0 -w dbase2 + ./rdbz -E 1000 -0 -a dbase2 dbase2.add + cmp dbase dbase2 + cmp dbase.dir dbase2.dir + cmp dbase.pag dbase2.pag + : build based on existing one, test extraction and readonly files + ./rdbz -E 1000 -0 -f dbase dbase2 + test "`cat dbase.used | wc -l`" -eq "`awk 'NR==2{print $$1}' dbase2.dir`" ; + test "`cat dbase.used | wc -l`" -eq "`awk 'NR==2{print $$2}' dbase2.dir`" ; + chmod -w dbase2.dir dbase2.pag + ./rdbz -E 1000 -x dbase2 dbase >dbase.temp + cmp dbase.used dbase.temp + : try some small case perversions + sed 's/\(@[^ ]*\)A/\1a/' dbase >dbase.ick + ./rdbz -E 1000 -x dbase2 dbase.ick >dbase.temp + cmp dbase.used dbase.temp + sed -n 's/A\([^ ]*@\)/a\1/p' dbase >dbase.ick + ./rdbz -x dbase2 dbase.ick >dbase.temp + test ! -s dbase.temp ; + rm -f dbase2.dir dbase2.pag + : try it without tags, case-insensitive, with case perversions + ./rdbz -E 1000 -0 -p '0 b 1' dbase2 + tr '[A-M][n-z]' '[a-m][N-Z]' dbase.ick + ./rdbz -E 1000 -x dbase2 dbase.ick >dbase.temp + cmp dbase.used dbase.temp + rm -f dbase.temp dbase.ick + : test various perversions of byte ordering + awk -f revbytes dbase.dir >dbase2.dir + chmod +x getmap + ./byteflip `./getmap dbase.dir` `./getmap dbase2.dir` dbase2.pag + cp dbase dbase2 + ./rdbz -E 1000 -0 -c dbase2 + awk -f altbytes dbase.dir >dbase2.dir + dd conv=swab dbase2.pag + ./rdbz -E 1000 -0 -c dbase2 + cp dbase2 dbase3 + ./rdbz -E 1000 -0 -f dbase2 dbase3 + ./rdbz -E 1000 -0 -c dbase3 + test " `./getmap dbase2.dir`" = " `./getmap dbase3.dir`" ; + : test massive overflow, throw in case sensitivity and tag mask + cp $(R2HIST) dbase + ./rdbz -E 1000 -0 -p '0 0 7ffc0000' dbase + ./rdbz -E 1000 -0 -cq dbase + sed 100q dbase | egrep '[aA].* ' | tr aA Aa >dbase.ick + ./rdbz -x dbase dbase.ick >dbase.temp + test ! -s dbase.temp ; + : check tag autoshrinking, tag size computing + test " `awk 'NR == 1 { print $$7 }' dbase.dir`" = " 8191" ; + ./rdbz -E 1000 -0 -f dbase dbase + test " `awk 'NR == 1 { print $$7 }' dbase.dir`" = " 8190" ; + cp $(RHIST) dbase + ./rdbz -E 1000 -0 -p '0 0 0' -T 1000000 dbase + test " `awk 'NR == 1 { print $$7 }' dbase.dir`" = " 127" ; + ./rdbz -E 1000 -0 -p '0 0 0' -T 500000000 dbase + test " `awk 'NR == 1 { print $$7 }' dbase.dir`" = " 3" ; + : success! + +rclean: + rm -f dbase dbase[23] dbase.* dbase[23].* fake fake.o random.o + rm -f rdbz rdbz.o rdbzmain.? $(RHIST) $(R2HIST) byteflip byteflip.o + rm -f histjunk core + test ! -d xx || rmdir xx + +clean: rclean + rm -f *.o dbz [a-z]dbz [a-z][a-z]dbz junk* PostScript.out + rm -f hist* dbase* *.bak mon.out gmon.out core dbm.h --- /dev/null +++ suck-4.3.2/libdbz/getmap @@ -0,0 +1,5 @@ +awk 'NR == 1 { + for (i = 9; i <= NF; i++) + printf "%s ", $i + printf "\n" +}' $* --- /dev/null +++ suck-4.3.2/libdbz/random.c @@ -0,0 +1,31 @@ +/* + * random-number generator for testing + */ +static unsigned long next = 1; + +/* + - range - generate a random number within an inclusive range + * + * Algorithm from ANSI C standard. Limitation: max-min <= 32767. + */ +int +range(min, max) +int min; +int max; +{ + register int temp; + + next = next * 1103515245 + 12345; + temp = (int)((next/65536)%32768); + return(temp%(max - min + 1) + min); +} + +/* + - seed - seed random number generator + */ +void +seed(n) +long n; +{ + next = (unsigned long)n; +} --- /dev/null +++ suck-4.3.2/libdbz/byteflip.c @@ -0,0 +1,34 @@ +#include + +#define MAXWORD 32 + +main(argc, argv) +int argc; +char *argv[]; +{ + register int len; + int inmap[MAXWORD]; + int outmap[MAXWORD]; + char in[MAXWORD]; + char out[MAXWORD]; + register int i; + register int a; + + a = 1; + len = atoi(argv[a++]); + if (len > MAXWORD) + abort(); /* kind of drastic... */ + for (i = 0; i < len; i++) + inmap[i] = atoi(argv[a++]); + if (atoi(argv[a++]) != len) + abort(); + for (i = 0; i < len; i++) + outmap[i] = atoi(argv[a++]); + + while (fread(in, 1, len, stdin) == len) { + for (i = 0; i < len; i++) + out[outmap[i]] = in[inmap[i]]; + fwrite(out, 1, len, stdout); + } + exit(0); +} --- /dev/null +++ suck-4.3.2/libdbz/dbzdbm.c @@ -0,0 +1,45 @@ +/* + * dbm emulation on top of dbz + */ + +#include + +/* + - dbminit - open a database, creating it (using defaults) if necessary + */ +int /* 0 success, -1 failure */ +dbminit(name) +char *name; +{ + return(dbzdbminit(name)); +} + +/* + - dbmclose - close a database + */ +int +dbmclose() +{ + return(dbzdbmclose()); +} + +/* + - fetch - get an entry from the database + */ +datum /* dptr NULL, dsize 0 means failure */ +fetch(key) +datum key; +{ + return(dbzdbmfetch(key)); +} + +/* + - store - add an entry to the database + */ +int /* 0 success, -1 failure */ +store(key, data) +datum key; +datum data; +{ + return(dbzdbmstore(key, data)); +} --- /dev/null +++ suck-4.3.2/libdbz/dbz.1 @@ -0,0 +1,221 @@ +.TH DBZ 1 "11 Feb 1992" +.BY "C News" +.SH NAME +dbz \- operate on dbz databases of text +.SH SYNOPSIS +.B dbz +[ +.BR \- { axmc } +] [ +.B \-t +c +] [ +.B \-l +length +] [ +.BR \- { qiue } +] [ +.B \-f +old +] [ +.B \-p +parms +] database file ... +.SH DESCRIPTION +.I Dbz +is a shell-level interface to the +.IR dbz (3z) +database routines for indexed access to a text file. +.PP +The +.I database +file must be a text file, +one line per database record, +with the key the first field on the line. +The +.B \-t +option sets the field-separator character; the default is tab. +Setting the separator character to NUL (with +.BR "\-t\ ''" ) +makes the whole line the key. +Lines must not exceed 1023 bytes in length including the newline; +this limit can be increased with the +.B \-l +option. +The limitations and restrictions of +.IR dbz (3z) +must also be observed; +in particular, it remains the user's responsibility to ensure that +no attempt is made to store two entries (whether identical or not) +with the same key. +.PP +In the absence of options, +.I dbz +creates a +.IR dbz (3z) +index for the database; +the index comprises files +.IB database .pag +and +.IB database .dir +in the same directory. +Any previous index is silently overwritten. +The +.BR \-a , +.BR \-x , +.BR \-m , +and +.B \-c +options specify other operations. +.PP +With +.BR \-a , +.I dbz +appends lines from the +.IR file (s) +(standard input if none) +to the database, updating both the +text file and the indexes. +.PP +With +.BR \-x , +.I dbz +reads keys from the +.IR file (s) +(standard input if none) +and prints (on standard output) the corresponding lines, if any, +from the database. +The input is in the form of database lines, although only the keys are +significant. +The +.B \-q +option makes +.B \-x +print the input lines whose keys are found instead of the database +lines; this is somewhat faster. +.PP +With +.BR \-m , +operation is the same as for +.B \-x +except that the keys which are \fInot\fR present in the database are printed. +.PP +With +.BR \-c , +.I dbz +checks the database for internal consistency. +The +.B \-q +option causes this check to be done more quickly but less thoroughly +(each key is looked up in the index, but no check is made to be sure +that the index entry points to the right place). +.PP +The +.B \-i +option suppresses the use of +.IR dbz (3z)'s +.I incore +facility. +This makes accesses slower, but keeps the files current +during updating +and reduces +startup/shutdown overhead. +.PP +Normally, +.I dbz +checks whether a key is already in the database before adding it. +The +.B \-u +option suppresses this check, speeding things up at the expense of safety. +.PP +A new index is normally created with default size, +case mapping, and tagging. +The default size is right for 90-100,000 records. +The default case mapping is right for RFC822 message-ids. +See +.IR dbz (3z) +for what tagging is about. +(Note, these defaults can be changed when +.IR dbz (3z) +is installed.) +.PP +If the +.B \-f +option is given, +size, case mapping, and tagging +are instead initialized based on the +database +.IR old . +This is mostly useful when +creating a new generation of an existing database. +(See the description of +.I dbzagain +in +.IR dbz (3z) +for details.) +.PP +If the +.B \-p +option is given, the +.I parms +string specifies the size, case mapping, and tagging. +If +.I parms +is a single decimal number, +that is taken as the expected number of records +in the index, with case mapping and tagging defaulted. +Alternatively, +.I parms +can be three fields\(ema decimal number, a case-mapping code character, and a +hexadecimal tag mask\(emseparated by white space. +The decimal number is, again, the expected number of records; +0 means ``use the default''. +See +.IR dbz (3z) +for possible choices of case-mapping code, +but in particular, +.B 0 +means ``no case mapping''. +See +.IR dbz (3z) +for details on tag masks; +0 means ``use the default''. +.PP +If the +.B \-e +option is given, the decimal number in +.B \-p +is taken to be the exact table size, not the expected number of records, +and invocation of +.I dbzsize +(see +.IR dbz (3z)) +to predict a good size for that number of records is suppressed. +.PP +The +.B \&.pag +file is normally about 6 bytes per record (based on the estimate given to +.B \-p +or the previous history of the +.B \-f +database). +The +.B \&.dir +file is tiny. +.SH SEE ALSO +dbz(3z) +.SH HISTORY +Written at U of Toronto by Henry Spencer, for the C News project. +See +.IR dbz (3z) +for the history of the underlying database routines. +.SH BUGS +There are a number of undocumented options with obscure effects, +meant for debugging and regression testing of +.IR dbz (3z). +.PP +Permissions for the index files probably ought to be taken from those +of the base file. +.PP +The line-length limit is a blemish, alleviated only slightly by +.BR \-l . --- /dev/null +++ suck-4.3.2/libdbz/README @@ -0,0 +1,17 @@ +This is the new, improved, lemon-freshened :-) dbz. + +Just "make" will get you dbz.o and the dbz program. "make r" runs an +extensive set of regression tests; most of the mysterious oddments lying +around here are to do with that. "make rclean" cleans up after "make r". + +You probably want to inspect the #ifdef list early in dbz.c before +compiling, although the defaults should work all right on most systems. + +If you are not building this as part of C News, you will need to change +the -I option in FLAGS in the Makefile to "-I.", and delete the DBMLIBS +and RFC lines entirely. That will break some of the regression tests; +at some point I'll fix this. + +If you are using this independently from C News, you probably still want +to look through ../notebook/problems, as some of the portability problems +described in there can affect dbz. --- /dev/null +++ suck-4.3.2/libdbz/firstlast25 @@ -0,0 +1,50 @@ + 600000000~- 90fz0706yo.1Env21x8b + 200000000~- +<1Hy.ufmjqe371x5.o@HEEl0tAp4> 700000000~- + 600000000~- + 700000000~- +<6kUzkf.v74@iC1iGj882RQ0zli> 400000000~- + 600000000~- +<.wVJi1DX42@5.4i6.jaZ6qw9Ln1.> 500000000~- + 300000000~- +<43hQ.5shbE7@912400.ajES6x0sXl.M> 400000000~- + 600000000~- +<923s5e67d5Oq085Y.1@6Pik68584> 900000000~- +<.5.n5cx5aD62i9q8@Ai60Sc.4x> 200000000~- +<9N9n@3.1ql87.yj2xFs.zLqI> 700000000~- Q2.kni8kZps7kF5uiEv32B38y4z.p +<.X.fw.6LtoT.0@pp6bp.5s6yh74.> 400000000~- +<54c1w@7..u1.99m9T4j.BNGBiK> 600000000~- .F3hb.OFh06V..p + 500000000~- + 000000000~- +<0C605s6plaAgfM.ap40@e6d66n.uv01W.j.8ph.> 100000000~- m.x7TY8.8DQ5 +<.2.14xdn.@D0g.W.uZ.75gyyg.q1G> 100000000~- +<.A..03.@5v..64.5v3.3tbjUo.> 500000000~- +<72..c19ms65.WCf0G3.@83seEG9nnhM.O.j22> 900000000~- + 000000000~- NPLL42XVfM +<6HO.nFal1ufl3.8b@3.n0k7a.IDgNy> 700000000~- Wv4j3Itccnh0Zp3 + 400000000~- k67.hvXwv6X745R4rh2ybuFN3n. +<62dIeg.fW92.ov375@x76mf5c6.37.v> 000000000~- + 900000000~- +<.9Xr.7V91..oe5CG.hX@p5x3jos3s27R6O3yj1> 400000000~- + 100000000~- + 200000000~- + 400000000~- +<87.W3r6is4.@svVqQCBiNqz400A.qwj> 200000000~- +<0liI7Lu0Mx435m7M99@87Xw.8j63.9.> 500000000~- + 200000000~- e27S.BKVD70P.o + 200000000~- +<.2.69hy3JT1@Aq3.r83o.9> 700000000~- +<.W7EurYppo4fhzs.I@8651m2W7v> 700000000~- +<3m02.@22074.a5ct2j3> 900000000~- +<.fy9Epa@.1.kNGCNokFwB8ezo1WM> 800000000~- + 900000000~- + 100000000~- 9A6Ejq5t55I4VJ6.q1 + 300000000~- + 400000000~- + 000000000~- +<.0p3G7novlrYz9kjI@Sx.2w.yqzerZl12781.k> 700000000~- +<51ny.pQ7ay4@nfU2l1f0ixG09584.m> 000000000~- 38K5bhK7cr6.bg.5MlC2Fxq06Ziuw. +<2.cau.9s@.n4Pk0Jd9g> 300000000~- + 300000000~- c8.t4Q0.8t0.m50 +<.t13789u5AqM4m3.z0T@P17e.ypf> 200000000~- q17z.fZ3.FyD533WthqZs8q7 + 100000000~- --- /dev/null +++ suck-4.3.2/libdbz/altbytes @@ -0,0 +1,7 @@ +NR == 1 { + printf "%s %s %s %s %s %s %s %s %s", $1, $2, $3, $4, $5, $6, $7, $8, $9 + for (i = 10; i <= NF; i += 2) + printf " %s %s", $(i+1), $i + printf "\n" +} +NR > 1 { print } --- /dev/null +++ suck-4.3.2/libdbz/dbzmain.c @@ -0,0 +1,598 @@ +/* + * dbz - use and test dbz in various ways + * + * -Log- + */ + +#include +#include +#include +#include +#include +#include + +#ifdef FUNNYSEEKS +#include +#else +#define SEEK_SET 0 +#endif + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +#ifndef lint +static char RCSid[] = "$Header$"; +#endif + +char *progname; + +char *inname = "(no file)"; /* filename for messages etc. */ +long lineno; /* line number for messages etc. */ + +char *base_name; +char *pagname; +char *dir_name; +char *str2dup(); +FILE *base; + +int op = 'b'; /* what to do, default build a new table */ +char *badop = "only one of -a -x -c -m -v can be given"; +int baseinput = 1; /* is the base file also the input? */ + +char *from = NULL; /* old table to use for dbzagain() */ +int omitzero = 0; /* omit lines tagged with 0 */ +long every = 0; /* report every n lines */ +int syncs = 0; /* dbzsync() on each report */ +int quick = 0; /* quick checking, not too thorough */ +int sweep = 0; /* sweep file checking all offsets */ +int useincore = 1; /* should we use incore facility? */ +long xxx = 0; /* debugging variable */ +int printx = 0; /* print xxx after all is done */ +int unique = 1; /* before store(), check with fetch() */ +int usefresh = 0; /* use dbzfresh? */ +long siz = 0; /* -p size */ +char map = 'C'; /* -p map */ +long tag = 0; /* -p tag mask */ +int exact = 0; /* do not run dbzsize(siz) */ +int dbzint = 1; /* use new interface? */ +char fs = '\t'; /* field separator, default tab */ +int unopen = 0; /* make base unopenable during dbminit? */ +char *change = NULL; /* chdir here before dbmclose */ +long tagsize = 0; /* if non-zero, file size for tag sizing */ +int dowt = 0; /* do writethrough? */ + +#define DEFBUF 1024 /* default line-buffer size */ +int buflen = DEFBUF; /* line length limit */ +char lbuf[DEFBUF]; +char *line = lbuf; +char cbuf[DEFBUF]; +char *cmp = cbuf; + +void fail(); +void dofile(); +void runs(); +void dosweep(); +void verify(); +void mkfiles(); +void crfile(); +void doline(); +void process(); +datum dofetch(); +int dostore(); + +#ifdef HAVERFCIZE +extern char *rfc822ize(); +#else +#define rfc822ize(n) (n) +#endif + +/* + - main - parse arguments and handle options + */ +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + int doruns = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "axcmvt:l:R0E:SqOiX:Yuf:p:eMUC:T:wd")) != EOF) + switch (c) { + case 'a': /* append to existing table */ + if (op != 'b') + fail(badop, ""); + op = 'a'; + baseinput = 0; + break; + case 'x': /* extract from existing table */ + if (op != 'b') + fail(badop, ""); + op = 'x'; + baseinput = 0; + break; + case 'c': /* check existing table */ + if (op != 'b') + fail(badop, ""); + op = 'c'; + break; + case 'm': /* extract missing (complement of -x) */ + if (op != 'b') + fail(badop, ""); + op = 'm'; + baseinput = 0; + break; + case 'v': /* verify that this is a dbz file */ + if (op != 'b') + fail(badop, ""); + op = 'v'; + break; + case 't': /* set field separator */ + if (strlen(optarg) > (size_t)1) + fail("only one field separator allowed", ""); + fs = *optarg; + break; + case 'l': /* override line-length limit */ + buflen = atoi(optarg) + 1; + if (buflen <= 2) + fail("bad -l value `%s'", optarg); + line = malloc(buflen); + cmp = malloc(buflen); + if (line == NULL || cmp == NULL) + fail("cannot allocate %s-byte buffers", optarg); + break; + case 'R': /* print run statistics */ + doruns = 1; + break; + case '0': /* omit lines tagged (by fake -t) with 0 */ + omitzero = 1; + break; + case 'E': /* report every n items */ + every = atol(optarg); + break; + case 'S': /* dbzsync() on each -E report */ + syncs = 1; + break; + case 'q': /* quick check or extract */ + quick = 1; + break; + case 'O': /* sweep file checking all offsets */ + sweep = 1; + break; + case 'i': /* don't use incore */ + useincore = 0; + break; + case 'X': /* set xxx */ + xxx = atoi(optarg); + break; + case 'Y': /* print xxx afterward */ + printx = 1; + break; + case 'u': /* don't check uniqueness */ + unique = 0; + break; + case 'f': /* init from existing table's parameters */ + from = optarg; + break; + case 'p': /* parameters for dbzfresh */ + if (sscanf(optarg, "%ld %1s %lx", &siz, &map, &tag) != 3) { + map = '?'; + tag = 0; + if (sscanf(optarg, "%ld", &siz) != 1) + fail("bad -n value `%s'", optarg); + } + usefresh = 1; + break; + case 'e': /* -p size is exact, don't dbzsize() it */ + exact = 1; + break; + case 'M': /* use old dbm interface + rfc822ize */ + dbzint = 0; + break; + case 'U': /* make base unopenable during init */ + unopen = 1; + break; + case 'C': /* change directories before dbmclose */ + change = optarg; + break; + case 'd': /* Debugging. */ + if (dbzdebug(1) < 0) + fail("dbz debugging not available", ""); + break; + case 'T': /* file size for tag sizing */ + tagsize = atol(optarg); + break; + case 'w': /* do writethrough */ + dowt = 1; + break; + case '?': + default: + errflg++; + break; + } + if (errflg || optind >= argc || (optind+1 < argc && baseinput)) { + fprintf(stderr, "usage: %s ", progname); + fprintf(stderr, "[-{axcmv}] database [file] ...\n"); + exit(2); + } + + (void) dbzincore(useincore); + (void) dbzwritethrough(dowt); + base_name = argv[optind]; + pagname = str2dup(base_name, ".pag"); + dir_name = str2dup(base_name, ".dir"); + + if (op == 'v') { + verify(dir_name); + /* NOTREACHED */ + } + + mkfiles(); + optind++; + + if (baseinput) /* implies no further arguments */ + process(base, base_name); + else if (optind >= argc) + process(stdin, "stdin"); + else + for (; optind < argc; optind++) + dofile(argv[optind]); + + if (change != NULL) + (void) chdir(change); + if (dbmclose() < 0) + fail("dbmclose failed", ""); + if (doruns) + runs(pagname); + if (sweep) + dosweep(base_name, pagname); + if (printx) + printf("%ld\n", xxx); + exit(0); +} + +/* + - verify - just check whether the .dir file looks right or not + */ +void /* does not return */ +verify(dir) +char *dir; +{ + FILE *f; + char buf[4]; + size_t n; + + f = fopen(dir, "r"); + if (f == NULL) + exit(1); + n = fread(buf, sizeof(buf), 1, f); + (void) fclose(f); + + if (n != 1 || memcmp(buf, "dbz ", (size_t)4) != 0) + exit(1); + + exit(0); + /* NOTREACHED */ +} + +/* + - dofile - open a file and invoke process() + */ +void +dofile(name) +char *name; +{ + register FILE *in; + + if (STREQ(name, "-")) + process(stdin, "-"); + else { + in = fopen(name, "r"); + if (in == NULL) + fail("cannot open `%s'", name); + process(in, name); + (void) fclose(in); + } +} + +/* + - mkfiles - create empty files and open them up + */ +void +mkfiles() +{ + if (op == 'b' && !dbzint) { + crfile(dir_name); + crfile(pagname); + } + + base = fopen(base_name, (op == 'a') ? "a" : "r"); + if (base == NULL) + fail("cannot open `%s'", base_name); + if (unopen) + (void) chmod(base_name, 0); + if (from != NULL) { + if (dbzagain(base_name, from) < 0) + fail("dbzagain(`%s'...) failed", base_name); + } else if (op == 'b' && dbzint) { + if (!exact) + siz = dbzsize(siz); + if (tagsize != 0) + tag = dbztagmask(tagsize); + if (dbzfresh(base_name, siz, (int)fs, map, tag) < 0) + fail("dbzfresh(`%s'...) failed", base_name); + } else if (dbminit(base_name) < 0) + fail("dbminit(`%s') failed", base_name); + if (unopen) + (void) chmod(base_name, 0600); /* hard to restore original */ +} + +/* + - crfile - create a file + */ +void +crfile(name) +char *name; +{ + register int f; + + f = creat(name, 0666); + if (f < 0) + fail("cannot create `%s'", name); + (void) close(f); +} + +/* + - process - process input file + */ +void +process(in, name) +FILE *in; +char *name; +{ + register long place; + + inname = name; + lineno = 0; + + for (;;) { + place = ftell(in); + if (fgets(line, buflen, in) == NULL) + return; + lineno++; + if (every > 0 && lineno%every == 0) { + fprintf(stderr, "%ld\n", lineno); + if (dbzsync() < 0) + fail("dbzsync failed", ""); + } + doline(line, place); + } + /* NOTREACHED */ +} + +/* + - doline - process input line + */ +void +doline(lp, inoffset) +char *lp; +long inoffset; +{ + register char *p; + register char pc; + datum key, value; + long place = inoffset; + register int shouldfind; + register int llen; + char keytext[DBZMAXKEY+1]; + + p = NULL; + if (fs != '\0') + p = strchr(lp, fs); + if (p == NULL) + p = lp + strlen(lp); + if (p > lp && *(p-1) == '\n') + p--; + if (p - lp > DBZMAXKEY) + fail("key of `%s' too long", lp); + pc = *p; + *p = '\0'; + (void) strcpy(keytext, lp); + *p = pc; + key.dptr = (dbzint) ? keytext : rfc822ize(keytext); + key.dsize = strlen(keytext)+1; + + switch (op) { + case 'a': + place = ftell(base); + llen = strlen(lp); + if (fwrite(lp, 1, llen, base) != llen) + fail("write error in `%s'", base_name); + /* FALLTHROUGH */ + case 'b': + if (omitzero && p != NULL && *(p+1) == '0') + return; + if (unique) { + value = dofetch(key); + if (value.dptr != NULL) + fail("`%s' already present", lp); + } + value.dptr = (char *)&place; + value.dsize = (int)sizeof(place); + if (dostore(key, value) < 0) + fail("store failed on `%s'", lp); + break; + case 'c': + value = dofetch(key); + shouldfind = (omitzero && p != NULL && *(p+1) == '0') ? 0 : 1; + if (!shouldfind && (value.dptr != NULL || value.dsize != 0)) + fail("`%s' found, shouldn't be", lp); + if (shouldfind && (value.dptr == NULL || + value.dsize != sizeof(place))) + fail("can't find `%s'", lp); + if (shouldfind && !quick) { + (void) memcpy((char *)&place, value.dptr, sizeof(place)); + if (place != inoffset) + fail("offset mismatch on `%s'", lp); + if (fseek(base, place, SEEK_SET) != 0) + fail("fseek failed on `%s'", lp); + if (fgets(cmp, buflen, base) == NULL) + fail("can't read line for `%s'", lp); + if (!STREQ(lp, cmp)) + fail("compare failed on `%s'", lp); + } + break; + case 'x': + value = dofetch(key); + if (value.dptr != NULL && !quick) { + (void) memcpy((char *)&place, value.dptr, sizeof(place)); + if (fseek(base, place, SEEK_SET) != 0) + fail("fseek failed on `%s'", lp); + if (fgets(cmp, buflen, base) == NULL) + fail("can't read line for `%s'", lp); + fputs(cmp, stdout); + } else if (value.dptr != NULL) + fputs(lp, stdout); + break; + case 'm': + value = dofetch(key); + if (value.dptr == NULL) { + fputs(keytext, stdout); + putchar('\n'); + } + break; + default: + fail("unknown operator -- can't happen", ""); + break; + } +} + +/* + - runs - print run statistics + */ +void +runs(file) +char *file; +{ + register FILE *fd; + long it; + register long run; + + fd = fopen(file, "r"); + if (fd == NULL) + fail("cannot reopen `%s'", file); + run = 0; + while (fread((char *)&it, sizeof(it), 1, fd) == 1) { + if (it != 0) + run++; + else if (run > 0) { + printf("%ld\n", run); + run = 0; + } + } + (void) fclose(fd); +} + +/* + - dosweep - sweep pag file checking for valid offsets + */ +void +dosweep(fn, pn) +char *fn; +char *pn; +{ + register FILE *pf; + long it; + char nl; + register FILE *hf; + + hf = fopen(fn, "r"); + if (hf == NULL) + fail("cannot reopen `%s'", fn); + pf = fopen(pn, "r"); + if (pf == NULL) + fail("cannot reopen `%s'", pn); + while (fread((char *)&it, sizeof(it), 1, pf) == 1) { + it = (it & 0x80000000) ? (it&~0xf8000000) : it; + if (it != 0 && it != 1) { /* 0 empty, 1 known okay */ + it--; /* get rid of bias */ + (void) fseek(hf, it-1, SEEK_SET); + nl = getc(hf); + if (nl != '\n') + fprintf(stderr, "offset 0%lo does not point to line\n", + (long)it); + } + } + (void) fclose(hf); + (void) fclose(pf); +} + +/* + - fail - complain and die + */ +void +fail(s1, s2) +char *s1; +char *s2; +{ +# define MAXS2 50 + char s2buf[MAXS2+10]; + + fprintf(stderr, "%s: (file `%s', line %ld) ", progname, inname, lineno); + if (strlen(s2) <= (size_t)MAXS2) + fprintf(stderr, s1, s2); + else { + sprintf(s2buf, "%.*s...", MAXS2, s2); + fprintf(stderr, s1, s2buf); + } + fprintf(stderr, "\n"); + exit(1); +} + +/* + - str2dup - concatenate strings and malloc result + */ +char * +str2dup(s1, s2) +char *s1; +char *s2; +{ + register char *p; + + p = malloc((size_t)strlen(s1) + strlen(s2) + 1); + if (p == NULL) + fail("can't allocate space for strings", ""); + (void) strcpy(p, s1); + (void) strcat(p, s2); + return(p); +} + +/* + - dofetch - do a fetch or dbzfetch + */ +datum +dofetch(key) +datum key; +{ + if (dbzint) + return(dbzfetch(key)); + else + return(fetch(key)); +} + +/* + - dostore - do a store or dbzstore + */ +int +dostore(key, value) +datum key; +datum value; +{ + if (dbzint) + return(dbzstore(key, value)); + else + return(store(key, value)); +} --- /dev/null +++ suck-4.3.2/libdbz/revbytes @@ -0,0 +1,7 @@ +NR == 1 { + printf "%s %s %s %s %s %s %s %s %s", $1, $2, $3, $4, $5, $6, $7, $8, $9 + for (i = NF; i > 9; i--) + printf " %s", $i + printf "\n" +} +NR > 1 { print } --- /dev/null +++ suck-4.3.2/libdbz/fake.c @@ -0,0 +1,140 @@ +/* + * fake - make up random lines resembling history-file entries, reproducibly + * + * -Log- + */ + +#include +#include +#include +#include +#include + +#define MAXSTR 500 /* For sizing strings -- DON'T use BUFSIZ! */ +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +#ifndef lint +static char RCSid[] = "$Header$"; +#endif + +int midonly = 0; /* just message ids, rest not realistic */ +int tag = 0; /* tag lines with random digit for later use */ +int expired = -1; /* percentage of lines to be expired */ + +int debug = 0; +char *progname; + +char *inname; /* filename for messages etc. */ +long lineno; /* line number for messages etc. */ + +void doline(); +void addchars(); +void seed(); + +/* + - main - parse arguments and handle options + */ +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + FILE *in; + struct stat statbuf; + extern int optind; + extern char *optarg; + void process(); + register long no; + char line[MAXSTR]; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "ms:te:d")) != EOF) + switch (c) { + case 'm': /* message-ids only */ + midonly = 1; + break; + case 's': /* seed */ + seed(atol(optarg)); + break; + case 't': /* tag lines with a random digit */ + tag = 1; + break; + case 'e': /* percentage to be expired */ + expired = atoi(optarg); + break; + case 'd': /* Debugging. */ + debug++; + break; + case '?': + default: + errflg++; + break; + } + if (errflg || optind != argc - 1) { + fprintf(stderr, "usage: %s ", progname); + fprintf(stderr, "[-m] [-s seed] length\n"); + exit(2); + } + + for (no = atol(argv[optind]); no > 0; no--) { + doline(line); + puts(line); + } + exit(0); +} + +/* + - doline - generate random history pseudo-line + */ +void +doline(buf) +char *buf; +{ + char tagch[2]; + + (void) strcpy(buf, "<"); + addchars(buf, range(4, 20)); + (void) strcat(buf, "@"); + addchars(buf, range(8, 20)); + if (midonly) + (void) strcat(buf, ">\tx"); + else { + if (tag) { + tagch[0] = "1234567890"[range(0,9)]; + tagch[1] = '\0'; + (void) strcat(buf, ">\t"); + (void) strcat(buf, tagch); + (void) strcat(buf, "00000000~-"); + } else + (void) strcat(buf, ">\t1234567890~-"); + } + if (range(1, 100) > expired) { + if (midonly) + (void) strcat(buf, "\tx"); + else { + (void) strcat(buf, "\t"); + addchars(buf, range(10, 30)); + } + } +} + +/* + - addchars - generate n random characters suitable for history file + */ +void +addchars(buf, len) +char *buf; +int len; +{ + register int i; + register char *p = buf + strlen(buf); + static char vocab[] = "1234567890.abcde.fghij.klmno.pqrst.uvwxyz.\ +1234567890.ABCDE.FGHIJ.KLMNO.PQRST.UVWXYZ.1234567890.\ +1234567890.abcde.fghij.klmno.pqrst.uvwxyz.1234567890"; + + for (i = len; i > 0; i--) + *p++ = vocab[range(0, sizeof(vocab)-2)]; + *p++ = '\0'; +} --- /dev/null +++ suck-4.3.2/libdbz/dbz.3z @@ -0,0 +1,547 @@ +.TH DBZ 3Z "3 Feb 1991" +.BY "C News" +.SH NAME +dbminit, fetch, store, dbmclose \- somewhat dbm-compatible database routines +.br +dbzfresh, dbzagain, dbzfetch, dbzstore \- database routines +.br +dbzsync, dbzsize, dbzincore, dbzcancel, dbzdebug \- database routines +.SH SYNOPSIS +.nf +.B #include +.PP +.B dbminit(base) +.B char *base; +.PP +.B datum +.B fetch(key) +.B datum key; +.PP +.B store(key, value) +.B datum key; +.B datum value; +.PP +.B dbmclose() +.PP +.B dbzfresh(base, size, fieldsep, cmap, tagmask) +.B char *base; +.B long size; +.B int fieldsep; +.B int cmap; +.B long tagmask; +.PP +.B dbzagain(base, oldbase) +.B char *base; +.B char *oldbase; +.PP +.B datum +.B dbzfetch(key) +.B datum key; +.PP +.B dbzstore(key, value) +.B datum key; +.B datum value; +.PP +.B dbzsync() +.PP +.B long +.B dbzsize(nentries) +.B long nentries; +.PP +.B dbzincore(newvalue) +.PP +.B dbzcancel() +.PP +.B dbzdebug(newvalue) +.SH DESCRIPTION +These functions provide an indexing system for rapid random access to a +text file (the +.I base +.IR file ). +Subject to certain constraints, they are call-compatible with +.IR dbm (3), +although they also provide some extensions. +(Note that they are +.I not +file-compatible with +.I dbm +or any variant thereof.) +.PP +In principle, +.I dbz +stores key-value pairs, where both key and value are arbitrary sequences +of bytes, specified to the functions by +values of type +.IR datum , +typedefed in the header file to be a structure with members +.I dptr +(a value of type +.I char * +pointing to the bytes) +and +.I dsize +(a value of type +.I int +indicating how long the byte sequence is). +.PP +In practice, +.I dbz +is more restricted than +.IR dbm . +A +.I dbz +database +must be an index into a base file, +with the database +.IR value s +being +.IR fseek (3) +offsets into the base file. +Each such +.I value +must ``point to'' a place in the base file where the corresponding +.I key +sequence is found. +A key can be no longer than +.SM DBZMAXKEY +(a constant defined in the header file) bytes. +No key can be an initial subsequence of another, +which in most applications requires that keys be +either bracketed or terminated in some way (see the +discussion of the +.I fieldsep +parameter of +.IR dbzfresh , +below, +for a fine point on terminators). +.PP +.I Dbminit +opens a database, +an index into the base file +.IR base , +consisting of files +.IB base .dir +and +.IB base .pag +which must already exist. +(If the database is new, they should be zero-length files.) +Subsequent accesses go to that database until +.I dbmclose +is called to close the database. +The base file need not exist at the time of the +.IR dbminit , +but it must exist before accesses are attempted. +.PP +.I Fetch +searches the database for the specified +.IR key , +returning the corresponding +.IR value +if any. +.I Store +stores the +.IR key - value +pair in the database. +.I Store +will fail unless the database files are writeable. +See below for a complication arising from case mapping. +.PP +.I Dbzfresh +is a variant of +.I dbminit +for creating a new database with more control over details. +Unlike for +.IR dbminit , +the database files need not exist: +they will be created if necessary, +and truncated in any case. +.PP +.IR Dbzfresh 's +.I size +parameter specifies the size of the first hash table within the database, +in key-value pairs. +Performance will be best if +.I size +is a prime number and +the number of key-value pairs stored in the database does not exceed +about 2/3 of +.IR size . +(The +.I dbzsize +function, given the expected number of key-value pairs, +will suggest a database size that meets these criteria.) +Assuming that an +.I fseek +offset is 4 bytes, +the +.B .pag +file will be +.RI 4* size +bytes +(the +.B .dir +file is tiny and roughly constant in size) +until +the number of key-value pairs exceeds about 80% of +.IR size . +(Nothing awful will happen if the database grows beyond 100% of +.IR size , +but accesses will slow down somewhat and the +.B .pag +file will grow somewhat.) +.PP +.IR Dbzfresh 's +.I fieldsep +parameter specifies the field separator in the base file. +If this is not +NUL (0), and the last character of a +.I key +argument is NUL, that NUL compares equal to either a NUL or a +.I fieldsep +in the base file. +This permits use of NUL to terminate key strings without requiring that +NULs appear in the base file. +The +.I fieldsep +of a database created with +.I dbminit +is the horizontal-tab character. +.PP +For use in news systems, various forms of case mapping (e.g. uppercase to +lowercase) in keys are available. +The +.I cmap +parameter to +.I dbzfresh +is a single character specifying which of several mapping algorithms to use. +Available algorithms are: +.RS +.TP +.B 0 +case-sensitive: no case mapping +.TP +.B B +same as +.B 0 +.TP +.B NUL +same as +.B 0 +.TP +.B = +case-insensitive: uppercase and lowercase equivalent +.TP +.B b +same as +.B = +.TP +.B C +RFC822 message-ID rules, case-sensitive before `@' (with certain exceptions) +and case-insensitive after +.TP +.B ? +whatever the local default is, normally +.B C +.RE +.PP +Mapping algorithm +.B 0 +(no mapping) is faster than the others and is overwhelmingly the correct +choice for most applications. +Unless compatibility constraints interfere, it is more efficient to pre-map +the keys, storing mapped keys in the base file, than to have +.I dbz +do the mapping on every search. +.PP +For historical reasons, +.I fetch +and +.I store +expect their +.I key +arguments to be pre-mapped, but expect unmapped keys in the base file. +.I Dbzfetch +and +.I dbzstore +do the same jobs but handle all case mapping internally, +so the customer need not worry about it. +.PP +.I Dbz +stores only the database +.IR value s +in its files, relying on reference to the base file to confirm a hit on a key. +References to the base file can be minimized, greatly speeding up searches, +if a little bit of information about the keys can be stored in the +.I dbz +files. +This is ``free'' if there are some unused bits in an +.I fseek +offset, +so that the offset can be +.I tagged +with some information about the key. +The +.I tagmask +parameter of +.I dbzfresh +allows specifying the location of unused bits. +.I Tagmask +should be a mask with +one group of +contiguous +.B 1 +bits. +The bits in the mask should +be unused (0) in +.I most +offsets. +The bit immediately above the mask (the +.I flag +bit) should be unused (0) in +.I all +offsets; +.I (dbz)store +will reject attempts to store a key-value pair in which the +.I value +has the flag bit on. +Apart from this restriction, tagging is invisible to the user. +As a special case, a +.I tagmask +of 1 means ``no tagging'', for use with enormous base files or +on systems with unusual offset representations. +.PP +A +.I size +of 0 +given to +.I dbzfresh +is synonymous with the local default; +the normal default is suitable for tables of 90-100,000 +key-value pairs. +A +.I cmap +of 0 (NUL) is synonymous with the character +.BR 0 , +signifying no case mapping +(note that the character +.B ? +specifies the local default mapping, +normally +.BR C ). +A +.I tagmask +of 0 is synonymous with the local default tag mask, +normally 0x7f000000 (specifying the top bit in a 32-bit offset +as the flag bit, and the next 7 bits as the mask, +which is suitable for base files up to circa 24MB). +Calling +.I dbminit(name) +with the database files empty is equivalent to calling +.IR dbzfresh(name,0,'\et','?',0) . +.PP +When databases are regenerated periodically, as in news, +it is simplest to pick the parameters for a new database based on the old one. +This also permits some memory of past sizes of the old database, so that +a new database size can be chosen to cover expected fluctuations. +.I Dbzagain +is a variant of +.I dbminit +for creating a new database as a new generation of an old database. +The database files for +.I oldbase +must exist. +.I Dbzagain +is equivalent to calling +.I dbzfresh +with the same field separator, case mapping, and tag mask as the old database, +and a +.I size +equal to the result of applying +.I dbzsize +to the largest number of entries in the +.I oldbase +database and its previous 10 generations. +.PP +When many accesses are being done by the same program, +.I dbz +is massively faster if its first hash table is in memory. +If an internal flag is 1, +an attempt is made to read the table in when +the database is opened, and +.I dbmclose +writes it out to disk again (if it was read successfully and +has been modified). +.I Dbzincore +sets the flag to +.I newvalue +(which should be 0 or 1) +and returns the previous value; +this does not affect the status of a database that has already been opened. +The default is 0. +The attempt to read the table in may fail due to memory shortage; +in this case +.I dbz +quietly falls back on its default behavior. +.IR Store s +to an in-memory database are not (in general) written out to the file +until +.IR dbmclose +or +.IR dbzsync , +so if robustness in the presence of crashes +or concurrent accesses +is crucial, in-memory databases +should probably be avoided. +.PP +.I Dbzsync +causes all buffers etc. to be flushed out to the files. +It is typically used as a precaution against crashes or concurrent accesses +when a +.IR dbz -using +process will be running for a long time. +It is a somewhat expensive operation, +especially +for an in-memory database. +.PP +.I Dbzcancel +cancels any pending writes from buffers. +This is typically useful only for in-core databases, since writes are +otherwise done immediately. +Its main purpose is to let a child process, in the wake of a +.IR fork , +do a +.I dbmclose +without writing its parent's data to disk. +.PP +If +.I dbz +has been compiled with debugging facilities available (which makes it +bigger and a bit slower), +.I dbzdebug +alters the value (and returns the previous value) of an internal flag +which (when 1; default is 0) causes +verbose and cryptic debugging output on standard output. +.PP +Concurrent reading of databases is fairly safe, +but there is no (inter)locking, +so concurrent updating is not. +.PP +The database files include a record of the byte order of the processor +creating the database, and accesses by processors with different byte +order will work, although they will be slightly slower. +Byte order is preserved by +.IR dbzagain . +However, +agreement on the size and internal structure of an +.I fseek +offset is necessary, as is consensus on +the character set. +.PP +An open database occupies three +.I stdio +streams and their corresponding file descriptors; +a fourth is needed for an in-memory database. +Memory consumption is negligible (except for +.I stdio +buffers) except for in-memory databases. +.SH SEE ALSO +dbz(1), dbm(3) +.SH DIAGNOSTICS +Functions returning +.I int +values return 0 for success, \-1 for failure. +Functions returning +.I datum +values return a value with +.I dptr +set to NULL for failure. +.I Dbminit +attempts to have +.I errno +set plausibly on return, but otherwise this is not guaranteed. +An +.I errno +of +.B EDOM +from +.I dbminit +indicates that the database did not appear to be in +.I dbz +format. +.SH HISTORY +The original +.I dbz +was written by +Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us). +Later contributions by David Butler and Mark Moraes. +Extensive reworking, +including this documentation, +by Henry Spencer (henry@zoo.toronto.edu) as +part of the C News project. +Hashing function by Peter Honeyman. +.SH BUGS +The +.I dptr +members of returned +.I datum +values point to static storage which is overwritten by later calls. +.PP +Unlike +.IR dbm , +.I dbz +will misbehave if an existing key-value pair is `overwritten' by +a new +.I (dbz)store +with the same key. +The user is responsible for avoiding this by using +.I (dbz)fetch +first to check for duplicates; +an internal optimization remembers the result of the +first search so there is minimal overhead in this. +.PP +Waiting until after +.I dbminit +to bring the base file into existence +will fail if +.IR chdir (2) +has been used meanwhile. +.PP +The RFC822 case mapper implements only a first approximation to the +hideously-complex RFC822 case rules. +.PP +The prime finder in +.I dbzsize +is not particularly quick. +.PP +Should implement the +.I dbm +functions +.IR delete , +.IR firstkey , +and +.IR nextkey . +.PP +On C implementations which trap integer overflow, +.I dbz +will refuse to +.I (dbz)store +an +.I fseek +offset equal to the greatest +representable +positive number, +as this would cause overflow in the biased representation used. +.PP +.I Dbzagain +perhaps ought to notice when many offsets +in the old database were +too big for +tagging, and shrink the tag mask to match. +.PP +Marking +.IR dbz 's +file descriptors +.RI close-on- exec +would be a better approach to the problem +.I dbzcancel +tries to address, but that's harder to do portably. --- /dev/null +++ suck-4.3.2/libdbz/dbz.c @@ -0,0 +1,1898 @@ +/* + +dbz.c V3.4 + +Copyright 1988 Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us) +You can use this code in any manner, as long as you leave my name on it +and don't hold me responsible for any problems with it. + +Hacked on by gdb@ninja.UUCP (David Butler); Sun Jun 5 00:27:08 CDT 1988 + +Various improvments + INCORE by moraes@ai.toronto.edu (Mark Moraes) + +Major reworking by Henry Spencer as part of the C News project. + +These routines replace dbm as used by the usenet news software +(it's not a full dbm replacement by any means). It's fast and +simple. It contains no AT&T code. + +In general, dbz's files are 1/20 the size of dbm's. Lookup performance +is somewhat better, while file creation is spectacularly faster, especially +if the incore facility is used. + +If you are seized by the urge to hack mmap() calls into this stuff, please +try to resist it. Instead, spend that energy beating on your system supplier +to fix his read() and write() calls to exploit the same memory-mapping +tricks mmap() uses. That way, all kinds of software can get more efficient +*without* having non-portable grunge like mmap() hacked into it. + +*/ + +#include +#include +#include +#include +#include +#include +#ifndef __STDC__ +extern int errno; +#endif + + +#include + +/* + * #ifdef index. "LIA" = "leave it alone unless you know what you're doing". + * + * FUNNYSEEKS SEEK_SET is not 0, get it from + * INDEX_SIZE backward compatibility with old dbz; avoid using this + * NMEMORY number of days of memory for use in sizing new table (LIA) + * INCORE backward compatibility with old dbz; use dbzincore() instead + * DBZDEBUG enable debugging + * DEFSIZE default table size (not as critical as in old dbz) + * OLDBNEWS default case mapping as in old B News; set NOBUFFER + * BNEWS default case mapping as in current B News; set NOBUFFER + * DEFCASE default case-map algorithm selector + * NOTAGS fseek offsets are strange, do not do tagging (see below) + * NPAGBUF size of .pag buffer, in longs (LIA) + * SHISTBUF size of ASCII-file buffer, in bytes (LIA) + * MAXRUN length of run which shifts to next table (see below) (LIA) + * OVERFLOW long-int arithmetic overflow must be avoided, will trap + * NOBUFFER do not buffer hash-table i/o, B News locking is defective + */ + +#ifdef FUNNYSEEKS +#include +#else +#define SEEK_SET 0 +#endif +#ifdef OVERFLOW +#include +#endif + +static int dbzversion = 3; /* for validating .dir file format */ + +/* + * The dbz database exploits the fact that when news stores a + * tuple, the `value' part is a seek offset into a text file, pointing to + * a copy of the `key' part. This avoids the need to store a copy of + * the key in the dbz files. However, the text file *must* exist and be + * consistent with the dbz files, or things will fail. + * + * The basic format of the database is a simple hash table containing the + * values. A value is stored by indexing into the table using a hash value + * computed from the key; collisions are resolved by linear probing (just + * search forward for an empty slot, wrapping around to the beginning of + * the table if necessary). Linear probing is a performance disaster when + * the table starts to get full, so a complication is introduced. The + * database is actually one *or more* tables, stored sequentially in the + * .pag file, and the length of linear-probe sequences is limited. The + * search (for an existing item or an empty slot) always starts in the + * first table, and whenever MAXRUN probes have been done in table N, + * probing continues in table N+1. This behaves reasonably well even in + * cases of massive overflow. There are some other small complications + * added, see comments below. + * + * The table size is fixed for any particular database, but is determined + * dynamically when a database is rebuilt. The strategy is to try to pick + * the size so the first table will be no more than 2/3 full, that being + * slightly before the point where performance starts to degrade. (It is + * desirable to be a bit conservative because the overflow strategy tends + * to produce files with holes in them, which is a nuisance.) + */ + +/* + * The following is for backward compatibility. + */ +#ifdef INDEX_SIZE +#define DEFSIZE INDEX_SIZE +#endif + +/* + * ANSI C says an offset into a file is a long, not an off_t, for some + * reason. This actually does simplify life a bit, but it's still nice + * to have a distinctive name for it. Beware, this is just for readability, + * don't try to change this. + */ +#define of_t long +#define SOF (sizeof(of_t)) + +/* + * We assume that unused areas of a binary file are zeros, and that the + * bit pattern of `(of_t)0' is all zeros. The alternative is rather + * painful file initialization. Note that okayvalue(), if OVERFLOW is + * defined, knows what value of an offset would cause overflow. + */ +#define VACANT ((of_t)0) +#define BIAS(o) ((o)+1) /* make any valid of_t non-VACANT */ +#define UNBIAS(o) ((o)-1) /* reverse BIAS() effect */ + +/* + * In a Unix implementation, or indeed any in which an of_t is a byte + * count, there are a bunch of high bits free in an of_t. There is a + * use for them. Checking a possible hit by looking it up in the base + * file is relatively expensive, and the cost can be dramatically reduced + * by using some of those high bits to tag the value with a few more bits + * of the key's hash. This detects most false hits without the overhead of + * seek+read+strcmp. We use the top bit to indicate whether the value is + * tagged or not, and don't tag a value which is using the tag bits itself. + * We're in trouble if the of_t representation wants to use the top bit. + * The actual bitmasks and offset come from the configuration stuff, + * which permits fiddling with them as necessary, and also suppressing + * them completely (by defining the masks to 0). We build pre-shifted + * versions of the masks for efficiency. + */ +static of_t tagbits; /* pre-shifted tag mask */ +static of_t taghere; /* pre-shifted tag-enable bit */ +static of_t tagboth; /* tagbits|taghere */ +#define HASTAG(o) ((o)&taghere) +#define TAG(o) ((o)&tagbits) +#define NOTAG(o) ((o)&~tagboth) +#define CANTAG(o) (((o)&tagboth) == 0) +#define MKTAG(v) (((v)<>= 1; + c.tagshift++; + } + c.tagmask = m; + c.tagenb = (m << 1) & ~m; + break; + } + + /* write it out */ + fn = enstring(name, dir); + if (fn == NULL) + return(-1); + f = fopen(fn, "w"); + free(fn); + if (f == NULL) { + DEBUG(("dbzfresh: unable to write config\n")); + return(-1); + } + if (putconf(f, &c) < 0) { + (void) fclose(f); + return(-1); + } + if (fclose(f) == EOF) { + DEBUG(("dbzfresh: fclose failure\n")); + return(-1); + } + + /* create/truncate .pag */ + fn = enstring(name, pag); + if (fn == NULL) + return(-1); + f = fopen(fn, "w"); + free(fn); + if (f == NULL) { + DEBUG(("dbzfresh: unable to create/truncate .pag file\n")); + return(-1); + } else + (void) fclose(f); + + /* and punt to dbzdbminit for the hard work */ + return(dbzdbminit(name)); +} + +/* + - dbzsize - what's a good table size to hold this many entries? + */ +long +dbzsize(contents) +long contents; /* 0 means what's the default */ +{ + register long n; + + if (contents <= 0) { /* foulup or default inquiry */ + DEBUG(("dbzsize: preposterous input (%ld)\n", contents)); + return(DEFSIZE); + } + n = (contents/2)*3; /* try to keep table at most 2/3 full */ + if (!(n&01)) /* make it odd */ + n++; + DEBUG(("dbzsize: tentative size %ld\n", n)); + while (!isprime(n)) /* and look for a prime */ + n += 2; + DEBUG(("dbzsize: final size %ld\n", n)); + + return(n); +} + +/* + - isprime - is a number prime? + * + * This is not a terribly efficient approach. + */ +static int /* predicate */ +isprime(x) +register long x; +{ + static int quick[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 0 }; + register int *ip; + register long div; + register long stop; + + /* hit the first few primes quickly to eliminate easy ones */ + /* this incidentally prevents ridiculously small tables */ + for (ip = quick; (div = *ip) != 0; ip++) + if (x%div == 0) { + DEBUG(("isprime: quick result on %ld\n", x)); + return(0); + } + + /* approximate square root of x */ + for (stop = x; x/stop < stop; stop >>= 1) + continue; + stop <<= 1; + + /* try odd numbers up to stop */ + for (div = *--ip + 2; div < stop; div += 2) + if (x%div == 0) + return(0); + + return(1); +} + +/* + - dbztagmask - what's a good tag mask for a file this size? + * + * This assumes that TAGENB is the high-order bit of a long. + */ +long +dbztagmask(filesize) +register long filesize; +{ + register long m; + register int nbits; + + /* + * First, see how many bits are unused. We cut it off at 7 on the + * theory that a 1-in-128 rate of false probes should be okay, given + * that the .pag file gets resized to limit the length of runs anyway. + */ + m = TAGENB << (TAGSHIFT-1); + nbits = 1; + while ((m&filesize) == 0 && nbits < 7) { /* extend downward */ + m |= m >> 1; + nbits++; + } + + if ((m&filesize) == 0) /* reached max bits and still fine */ + return(m); + + /* We now have a mask that is one bit too big. */ + m &= m << 1; /* shorten it */ + + if (m == 0) /* file is just too big */ + return(1); + + return(m); +} + +/* + - dbzagain - set up a new database to be a rebuild of an old one + */ +int /* 0 success, -1 failure */ +dbzagain(name, oldname) +char *name; /* base name; .dir and .pag must exist */ +char *oldname; /* base name; all must exist */ +{ + register char *fn; + struct dbzconfig c; + register int i; + register long top; + register FILE *f; + register int newtable; + register long newsize; + + if (pagf != NULL) { + DEBUG(("dbzagain: database already open\n")); + return(-1); + } + + /* pick up the old configuration */ + fn = enstring(oldname, dir); + if (fn == NULL) + return(-1); + f = fopen(fn, "r"); + free(fn); + if (f == NULL) { + DEBUG(("dbzagain: cannot open old .dir file\n")); + return(-1); + } + i = getconf(f, (FILE *)NULL, &c); + (void) fclose(f); + if (i < 0) { + DEBUG(("dbzagain: getconf failed\n")); + return(-1); + } + + /* tinker with it */ + /* first, find peak of usage history, if there's enough history */ + top = 0; + newtable = 0; + for (i = 0; i < NUSEDS; i++) { + if (top < c.used[i]) + top = c.used[i]; + if (c.used[i] == 0) + newtable = 1; /* hasn't got full usage history yet */ + } + if (top == 0) { + DEBUG(("dbzagain: old table has no contents!\n")); + newtable = 1; + } + + /* shift the history, and decide on table size */ + for (i = NUSEDS-1; i > 0; i--) { + c.used[i] = c.used[i-1]; + c.ntagless[i] = c.ntagless[i-1]; + } + c.used[0] = 0; + c.ntagless[0] = 0; + newsize = dbzsize(top); + if (!newtable || newsize > c.tsize) /* don't shrink new table */ + c.tsize = newsize; + + /* decide whether the tag needs changing */ + if (c.ntagless[1] != 0) { + c.tagmask &= c.tagmask << 1; /* clear bottom bit */ + if (c.tagmask == 0) /* oops, no more room... */ + c.tagenb = 0; /* just can't tag at all */ + } + /* + * You might think that you'd want to adaptively grow the tag + * as well as shrinking it. It's very hard to do that well, + * so for now we don't try. + */ + + /* write it out */ + fn = enstring(name, dir); + if (fn == NULL) + return(-1); + f = fopen(fn, "w"); + free(fn); + if (f == NULL) { + DEBUG(("dbzagain: unable to write new .dir\n")); + return(-1); + } + i = putconf(f, &c); + (void) fclose(f); + if (i < 0) { + DEBUG(("dbzagain: putconf failed\n")); + return(-1); + } + + /* create/truncate .pag */ + fn = enstring(name, pag); + if (fn == NULL) + return(-1); + f = fopen(fn, "w"); + free(fn); + if (f == NULL) { + DEBUG(("dbzagain: unable to create/truncate .pag file\n")); + return(-1); + } else + (void) fclose(f); + + /* and let dbzdbminit do the work */ + return(dbzdbminit(name)); +} + +/* + - dbzdbminit - open a database, creating it (using defaults) if necessary + * + * We try to leave errno set plausibly, to the extent that underlying + * functions permit this, since many people consult it if dbzdbminit() fails. + */ +int /* 0 success, -1 failure */ +dbzdbminit(name) +char *name; +{ + register int i; + register size_t s; + register char *dirfname; + register char *pagfname; + + if (pagf != NULL) { + DEBUG(("dbzdbminit: dbzdbminit already called once\n")); + errno = 0; + return(-1); + } + + /* open the .dir file */ + dirfname = enstring(name, dir); + if (dirfname == NULL) + return(-1); + dirf = fopen(dirfname, "r+"); + if (dirf == NULL) { + dirf = fopen(dirfname, "r"); + dirronly = 1; + } else + dirronly = 0; + free(dirfname); + if (dirf == NULL) { + DEBUG(("dbzdbminit: can't open .dir file\n")); + return(-1); + } + if (callback != NULL) + (*callback)(dirf); + + /* open the .pag file */ + pagfname = enstring(name, pag); + if (pagfname == NULL) { + (void) fclose(dirf); + return(-1); + } + pagf = fopen(pagfname, "r+b"); + if (pagf == NULL) { + pagf = fopen(pagfname, "rb"); + if (pagf == NULL) { + DEBUG(("dbzdbminit: .pag open failed\n")); + (void) fclose(dirf); + free(pagfname); + return(-1); + } + pagronly = 1; + } else if (dirronly) + pagronly = 1; + else + pagronly = 0; +#ifdef NOBUFFER + /* + * B News does not do adequate locking on its database accesses. + * Why it doesn't get into trouble using dbm is a mystery. In any + * case, doing unbuffered i/o does not cure the problem, but does + * enormously reduce its incidence. + */ + (void) setbuf(pagf, (char *)NULL); +#else +#ifdef _IOFBF + (void) setvbuf(pagf, (char *)pagbuf, _IOFBF, sizeof(pagbuf)); +#endif +#endif + pagpos = -1; + /* don't free pagfname, need it below */ + if (callback != NULL) + (*callback)(pagf); + + /* open the base file */ + basef = fopen(name, "r"); + if (basef == NULL) { + DEBUG(("dbzdbminit: basefile open failed\n")); + basefname = enstring(name, ""); + if (basefname == NULL) { + (void) fclose(pagf); + (void) fclose(dirf); + free(pagfname); + pagf = NULL; + return(-1); + } + } else + basefname = NULL; +#ifdef _IOFBF + if (basef != NULL) + (void) setvbuf(basef, basebuf, _IOFBF, sizeof(basebuf)); +#endif + if (callback != NULL) + (*callback)(basef); + + /* pick up configuration */ + if (getconf(dirf, pagf, &conf) < 0) { + DEBUG(("dbzdbminit: getconf failure\n")); + (void) fclose(basef); + (void) fclose(pagf); + (void) fclose(dirf); + free(pagfname); + pagf = NULL; + errno = EDOM; /* kind of a kludge, but very portable */ + return(-1); + } + tagbits = conf.tagmask << conf.tagshift; + taghere = conf.tagenb << conf.tagshift; + tagboth = tagbits | taghere; + mybytemap(mybmap); + bytesame = 1; + for (i = 0; i < SOF; i++) + if (mybmap[i] != conf.bytemap[i]) + bytesame = 0; + + /* get first table into core, if it looks desirable and feasible */ + s = (size_t)conf.tsize * SOF; + if (incore && (of_t)(s/SOF) == conf.tsize) { + bufpagf = fopen(pagfname, (pagronly) ? "rb" : "r+b"); + if (bufpagf != NULL) { + corepag = getcore(bufpagf); + if (callback != NULL) + (*callback)(bufpagf); + } + } else { + bufpagf = NULL; + corepag = NULL; + } + free(pagfname); + + /* misc. setup */ + crcinit(); + written = 0; + prevp = FRESH; + DEBUG(("dbzdbminit: succeeded\n")); + return(0); +} + +/* + - enstring - concatenate two strings into a malloced area + */ +static char * /* NULL if malloc fails */ +enstring(s1, s2) +char *s1; +char *s2; +{ + register char *p; + + p = malloc((size_t)strlen(s1) + (size_t)strlen(s2) + 1); + if (p != NULL) { + (void) strcpy(p, s1); + (void) strcat(p, s2); + } else { + DEBUG(("enstring(%s, %s) out of memory\n", s1, s2)); + } + return(p); +} + +/* + - dbzdbmclose - close a database + */ +int +dbzdbmclose() +{ + register int ret = 0; + + if (pagf == NULL) { + DEBUG(("dbzdbmclose: not opened!\n")); + return(-1); + } + + if (fclose(pagf) == EOF) { + DEBUG(("dbzdbmclose: fclose(pagf) failed\n")); + ret = -1; + } + pagf = basef; /* ensure valid pointer; dbzsync checks it */ + if (dbzsync() < 0) + ret = -1; + if (bufpagf != NULL && fclose(bufpagf) == EOF) { + DEBUG(("dbzdbmclose: fclose(bufpagf) failed\n")); + ret = -1; + } + if (corepag != NULL) + free((char *)corepag); + corepag = NULL; + if (fclose(basef) == EOF) { + DEBUG(("dbzdbmclose: fclose(basef) failed\n")); + ret = -1; + } + if (basefname != NULL) + free(basefname); + basef = NULL; + pagf = NULL; + if (fclose(dirf) == EOF) { + DEBUG(("dbzdbmclose: fclose(dirf) failed\n")); + ret = -1; + } + + DEBUG(("dbzdbmclose: %s\n", (ret == 0) ? "succeeded" : "failed")); + return(ret); +} + +/* + - dbzsync - push all in-core data out to disk + */ +int +dbzsync() +{ + register int ret = 0; + + if (pagf == NULL) { + DEBUG(("dbzsync: not opened!\n")); + return(-1); + } + if (!written) + return(0); + + if (corepag != NULL && !writethrough) { + if (putcore(corepag, bufpagf) < 0) { + DEBUG(("dbzsync: putcore failed\n")); + ret = -1; + } + } + if (!conf.olddbz) + if (putconf(dirf, &conf) < 0) + ret = -1; + + DEBUG(("dbzsync: %s\n", (ret == 0) ? "succeeded" : "failed")); + return(ret); +} + +/* + - dbzcancel - cancel writing of in-core data + * Mostly for use from child processes. + * Note that we don't need to futz around with stdio buffers, because we + * always fflush them immediately anyway and so they never have stale data. + */ +int +dbzcancel() +{ + if (pagf == NULL) { + DEBUG(("dbzcancel: not opened!\n")); + return(-1); + } + + written = 0; + return(0); +} + +/* + - dbzfetch - fetch() with case mapping built in + */ +datum +dbzfetch(key) +datum key; +{ + char buffer[DBZMAXKEY + 1]; + datum mappedkey; + register size_t keysize; + + DEBUG(("dbzfetch: (%s)\n", key.dptr)); + + /* Key is supposed to be less than DBZMAXKEY */ + keysize = key.dsize; + if (keysize >= DBZMAXKEY) { + keysize = DBZMAXKEY; + DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY)); + } + + mappedkey.dptr = mapcase(buffer, key.dptr, keysize); + buffer[keysize] = '\0'; /* just a debug aid */ + mappedkey.dsize = keysize; + + return(dbzdbmfetch(mappedkey)); +} + +/* + - dbzdbmfetch - get an entry from the database + * + * Disgusting fine point, in the name of backward compatibility: if the + * last character of "key" is a NUL, that character is (effectively) not + * part of the comparison against the stored keys. + */ +datum /* dptr NULL, dsize 0 means failure */ +dbzdbmfetch(key) +datum key; +{ + char buffer[DBZMAXKEY + 1]; + static of_t key_ptr; /* return value points here */ + datum output; + register size_t keysize; + register size_t cmplen; + register char *sepp; + + DEBUG(("dbzdbmfetch: (%s)\n", key.dptr)); + output.dptr = NULL; + output.dsize = 0; + prevp = FRESH; + + /* Key is supposed to be less than DBZMAXKEY */ + keysize = key.dsize; + if (keysize >= DBZMAXKEY) { + keysize = DBZMAXKEY; + DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY)); + } + + if (pagf == NULL) { + DEBUG(("dbzdbmfetch: database not open!\n")); + return(output); + } else if (basef == NULL) { /* basef didn't exist yet */ + basef = latebase(); + if (basef == NULL) + return(output); + } + + cmplen = keysize; + sepp = &conf.fieldsep; + if (key.dptr[keysize-1] == '\0') { + cmplen--; + sepp = &buffer[keysize-1]; + } + start(&srch, &key, FRESH); + while ((key_ptr = search(&srch)) != NOTFOUND) { + DEBUG(("got 0x%lx\n", (long)key_ptr)); + + /* fetch the key */ + if (fseek(basef, key_ptr, SEEK_SET) != 0) { + DEBUG(("dbzdbmfetch: seek failed\n")); + return(output); + } + if (fread(buffer, 1, keysize, basef) != keysize) { + DEBUG(("dbzdbmfetch: read failed\n")); + return(output); + } + + /* try it */ + buffer[keysize] = '\0'; /* terminated for DEBUG */ + (void) mapcase(buffer, buffer, keysize); + DEBUG(("dbzdbmfetch: buffer (%s) looking for (%s) size = %d\n", + buffer, key.dptr, keysize)); + if (memcmp(key.dptr, buffer, cmplen) == 0 && + (*sepp == conf.fieldsep || *sepp == '\0')) { + /* we found it */ + output.dptr = (char *)&key_ptr; + output.dsize = SOF; + DEBUG(("dbzdbmfetch: successful\n")); + return(output); + } + } + + /* we didn't find it */ + DEBUG(("dbzdbmfetch: failed\n")); + prevp = &srch; /* remember where we stopped */ + return(output); +} + +/* + - latebase - try to open a base file that wasn't there at the start + */ +static FILE * +latebase() +{ + register FILE *it; + + if (basefname == NULL) { + DEBUG(("latebase: name foulup\n")); + return(NULL); + } + it = fopen(basefname, "r"); + if (it == NULL) { + DEBUG(("latebase: still can't open base\n")); + } else { + DEBUG(("latebase: late open succeeded\n")); + free(basefname); + basefname = NULL; +#ifdef _IOFBF + (void) setvbuf(it, basebuf, _IOFBF, sizeof(basebuf)); +#endif + if (callback != NULL) + (*callback)(it); + } + return(it); +} + +/* + - dbzstore - store() with case mapping built in + */ +int +dbzstore(key, data) +datum key; +datum data; +{ + char buffer[DBZMAXKEY + 1]; + datum mappedkey; + register size_t keysize; + + DEBUG(("dbzstore: (%s)\n", key.dptr)); + + /* Key is supposed to be less than DBZMAXKEY */ + keysize = key.dsize; + if (keysize >= DBZMAXKEY) { + DEBUG(("dbzstore: key size too big (%d)\n", key.dsize)); + return(-1); + } + + mappedkey.dptr = mapcase(buffer, key.dptr, keysize); + buffer[keysize] = '\0'; /* just a debug aid */ + mappedkey.dsize = keysize; + + return(dbzdbmstore(mappedkey, data)); +} + +/* + - dbzdbmstore - add an entry to the database + */ +int /* 0 success, -1 failure */ +dbzdbmstore(key, data) +datum key; +datum data; +{ + of_t value; + + if (pagf == NULL) { + DEBUG(("dbzdbmstore: database not open!\n")); + return(-1); + } else if (basef == NULL) { /* basef didn't exist yet */ + basef = latebase(); + if (basef == NULL) + return(-1); + } + if (pagronly) { + DEBUG(("dbzdbmstore: database open read-only\n")); + return(-1); + } + if (data.dsize != SOF) { + DEBUG(("dbzdbmstore: value size wrong (%d)\n", data.dsize)); + return(-1); + } + if (key.dsize >= DBZMAXKEY) { + DEBUG(("dbzdbmstore: key size too big (%d)\n", key.dsize)); + return(-1); + } + + /* copy the value in to ensure alignment */ + (void) memcpy((char *)&value, data.dptr, SOF); + DEBUG(("dbzdbmstore: (%s, %ld)\n", key.dptr, (long)value)); + if (!okayvalue(value)) { + DEBUG(("dbzdbmstore: reserved bit or overflow in 0x%lx\n", value)); + return(-1); + } + + /* find the place, exploiting previous search if possible */ + start(&srch, &key, prevp); + while (search(&srch) != NOTFOUND) + continue; + + prevp = FRESH; + conf.used[0]++; + DEBUG(("dbzdbmstore: used count %ld\n", conf.used[0])); + written = 1; + return(set(&srch, value)); +} + +/* + - dbzincore - control attempts to keep .pag file in core + */ +int /* old setting */ +dbzincore(value) +int value; +{ + register int old = incore; + + incore = value; + return(old); +} + +/* + - dbzwritethrough - enable/disable immediate writing to disk of in-core writes + */ +int /* old setting */ +dbzwritethrough(value) +int value; +{ + register int old = writethrough; + + writethrough = value; + return(old); +} + +/* + - dbzfiledesc - provide hook for doing obscene things to file descriptors + */ +typedef void (*fp)(); +fp +dbzfiledesc(diddler) +void (*diddler)(); /* NULL means do nothing */ +{ + register void (*old)() = callback; + + callback = diddler; + return(old); +} + +/* + - getconf - get configuration from .dir file + */ +static int /* 0 success, -1 failure */ +getconf(df, pf, cp) +register FILE *df; /* NULL means just give me the default */ +register FILE *pf; /* NULL means don't care about .pag */ +register struct dbzconfig *cp; +{ + register int c; + register int i; + int err = 0; + + c = (df != NULL) ? getc(df) : EOF; + if (c == EOF) { /* empty file, no configuration known */ + cp->olddbz = 0; + if (df != NULL && pf != NULL && getc(pf) != EOF) + cp->olddbz = 1; + cp->tsize = DEFSIZE; + cp->fieldsep = '\t'; + for (i = 0; i < NUSEDS; i++) { + cp->used[i] = 0; + cp->ntagless[i] = 0; + } + cp->valuesize = SOF; + mybytemap(cp->bytemap); + cp->casemap = DEFCASE; + cp->tagenb = TAGENB; + cp->tagmask = TAGMASK; + cp->tagshift = TAGSHIFT; + DEBUG(("getconf: defaults (%ld, %c, (0x%lx/0x%lx<<%d))\n", + cp->tsize, cp->casemap, cp->tagenb, + cp->tagmask, cp->tagshift)); + return(0); + } + (void) ungetc(c, df); + + /* first line, the vital stuff */ + if (getc(df) != 'd' || getc(df) != 'b' || getc(df) != 'z') + err = -1; + if (getno(df, &err) != dbzversion) + err = -1; + cp->tsize = getno(df, &err); + cp->fieldsep = (char)getno(df, &err); + while ((c = getc(df)) == ' ') + continue; + cp->casemap = c; + cp->tagenb = getno(df, &err); + cp->tagmask = getno(df, &err); + cp->tagshift = getno(df, &err); + cp->valuesize = getno(df, &err); + if (cp->valuesize != SOF) { + DEBUG(("getconf: wrong of_t size (%d)\n", cp->valuesize)); + err = -1; + cp->valuesize = SOF; /* to protect the loops below */ + } + for (i = 0; i < cp->valuesize; i++) + cp->bytemap[i] = getno(df, &err); + if (getc(df) != '\n') + err = -1; + DEBUG(("size %ld, sep %d, cmap %c, tags 0x%lx/0x%lx<<%d, ", cp->tsize, + cp->fieldsep, cp->casemap, cp->tagenb, cp->tagmask, + cp->tagshift)); + DEBUG(("bytemap (%d)", cp->valuesize)); +#ifdef DBZDEBUG + for (i = 0; i < cp->valuesize; i++) { + DEBUG((" %d", cp->bytemap[i])); + } +#endif + DEBUG(("\n")); + + /* second line, the usages */ + for (i = 0; i < NUSEDS; i++) + cp->used[i] = getno(df, &err); + if (getc(df) != '\n') + err = -1; + DEBUG(("used %ld %ld %ld...\n", cp->used[0], cp->used[1], cp->used[2])); + + /* third line, currently only the tagless count */ + if ((c = getc(df)) != EOF) { + (void) ungetc(c, df); + for (i = 0; i < NUSEDS; i++) + cp->ntagless[i] = getno(df, &err); + if (getc(df) != '\n') + err = -1; + } else + for (i = 0; i < NUSEDS; i++) + cp->ntagless[i] = 0; + + if (err < 0) { + DEBUG(("getconf error\n")); + return(-1); + } + return(0); +} + +/* + - getno - get a long + */ +static long +getno(f, ep) +FILE *f; +int *ep; +{ + register char *p; +# define MAXN 50 + char getbuf[MAXN]; + register int c; + + while ((c = getc(f)) == ' ') + continue; + if (c == EOF || c == '\n') { + DEBUG(("getno: missing number\n")); + *ep = -1; + return(0); + } + p = getbuf; + *p++ = c; + while ((c = getc(f)) != EOF && c != '\n' && c != ' ') + if (p < &getbuf[MAXN-1]) + *p++ = c; + if (c == EOF) { + DEBUG(("getno: EOF\n")); + *ep = -1; + } else + (void) ungetc(c, f); + *p = '\0'; + + if (strspn(getbuf, "-1234567890") != strlen(getbuf)) { + DEBUG(("getno: `%s' non-numeric\n", getbuf)); + *ep = -1; + } + return(atol(getbuf)); +} + +/* + - putconf - write configuration to .dir file + */ +static int /* 0 success, -1 failure */ +putconf(f, cp) +register FILE *f; +register struct dbzconfig *cp; +{ + register int i; + register int ret = 0; + + if (fseek(f, (of_t)0, SEEK_SET) != 0) { + DEBUG(("fseek failure in putconf\n")); + ret = -1; + } + fprintf(f, "dbz %d %ld %d %c %ld %ld %d %d", dbzversion, cp->tsize, + cp->fieldsep, cp->casemap, cp->tagenb, + cp->tagmask, cp->tagshift, cp->valuesize); + for (i = 0; i < cp->valuesize; i++) + fprintf(f, " %d", cp->bytemap[i]); + fprintf(f, "\n"); + for (i = 0; i < NUSEDS; i++) + fprintf(f, "%ld%c", cp->used[i], (i < NUSEDS-1) ? ' ' : '\n'); + for (i = 0; i < NUSEDS; i++) + fprintf(f, "%ld%c", cp->ntagless[i], (i < NUSEDS-1) ? ' ' : '\n'); + + (void) fflush(f); + if (ferror(f)) + ret = -1; + + DEBUG(("putconf status %d\n", ret)); + return(ret); +} + +/* + - getcore - try to set up an in-core copy of .pag file + */ +static of_t * /* pointer to copy, or NULL */ +getcore(f) +FILE *f; +{ + register of_t *p; + register size_t i; + register size_t nread; + register of_t *it; + + it = (of_t *)malloc((size_t)conf.tsize * SOF); + if (it == NULL) { + DEBUG(("getcore: malloc failed\n")); + return(NULL); + } + + nread = fread((char *)it, SOF, (size_t)conf.tsize, f); + if (ferror(f)) { + DEBUG(("getcore: read failed\n")); + free((char *)it); + return(NULL); + } + + p = it + nread; + i = (size_t)conf.tsize - nread; + while (i-- > 0) + *p++ = VACANT; + + return(it); +} + +/* + - putcore - try to rewrite an in-core table + */ +static int /* 0 okay, -1 fail */ +putcore(tab, f) +of_t *tab; +FILE *f; +{ + if (fseek(f, (of_t)0, SEEK_SET) != 0) { + DEBUG(("fseek failure in putcore\n")); + return(-1); + } + (void) fwrite((char *)tab, SOF, (size_t)conf.tsize, f); + (void) fflush(f); + return((ferror(f)) ? -1 : 0); +} + +/* + - start - set up to start or restart a search + */ +static void +start(sp, kp, osp) +register struct searcher *sp; +register datum *kp; +register struct searcher *osp; /* may be FRESH, i.e. NULL */ +{ + register long h; + + h = hash(kp->dptr, kp->dsize); + if (osp != FRESH && osp->hash == h) { + if (sp != osp) + *sp = *osp; + DEBUG(("search restarted\n")); + } else { + sp->hash = h; + sp->tag = MKTAG(h / conf.tsize); + DEBUG(("tag 0x%lx\n", sp->tag)); + sp->place = h % conf.tsize; + sp->tabno = 0; + sp->run = (conf.olddbz) ? conf.tsize : MAXRUN; + sp->aborted = 0; + } + sp->seen = 0; +} + +/* + - search - conduct part of a search + */ +static of_t /* NOTFOUND if we hit VACANT or error */ +search(sp) +register struct searcher *sp; +{ + register of_t dest; + register of_t value; + of_t val; /* buffer for value (can't fread register) */ + register of_t place; + + if (sp->aborted) + return(NOTFOUND); + + for (;;) { + /* determine location to be examined */ + place = sp->place; + if (sp->seen) { + /* go to next location */ + if (--sp->run <= 0) { + sp->tabno++; + sp->run = MAXRUN; + } + place = (place+1)%conf.tsize + sp->tabno*conf.tsize; + sp->place = place; + } else + sp->seen = 1; /* now looking at current location */ + DEBUG(("search @ %ld\n", place)); + + /* get the tagged value */ + if (corepag != NULL && place < conf.tsize) { + DEBUG(("search: in core\n")); + value = MAPIN(corepag[place]); + } else { + /* seek, if necessary */ + dest = place * SOF; + if (pagpos != dest) { + if (fseek(pagf, dest, SEEK_SET) != 0) { + DEBUG(("search: seek failed\n")); + pagpos = -1; + sp->aborted = 1; + return(NOTFOUND); + } + pagpos = dest; + } + + /* read it */ + if (fread((char *)&val, sizeof(val), 1, pagf) == 1) + value = MAPIN(val); + else if (ferror(pagf)) { + DEBUG(("search: read failed\n")); + pagpos = -1; + sp->aborted = 1; + return(NOTFOUND); + } else + value = VACANT; + + /* and finish up */ + pagpos += sizeof(val); + } + + /* vacant slot is always cause to return */ + if (value == VACANT) { + DEBUG(("search: empty slot\n")); + return(NOTFOUND); + }; + + /* check the tag */ + value = UNBIAS(value); + DEBUG(("got 0x%lx\n", value)); + if (!HASTAG(value)) { + DEBUG(("tagless\n")); + return(value); + } else if (TAG(value) == sp->tag) { + DEBUG(("match\n")); + return(NOTAG(value)); + } else { + DEBUG(("mismatch 0x%lx\n", TAG(value))); + } + } + /* NOTREACHED */ +} + +/* + - okayvalue - check that a value can be stored + */ +static int /* predicate */ +okayvalue(value) +of_t value; +{ + if (HASTAG(value)) + return(0); +#ifdef OVERFLOW + if (value == LONG_MAX) /* BIAS() and UNBIAS() will overflow */ + return(0); +#endif + return(1); +} + +/* + - set - store a value into a location previously found by search + */ +static int /* 0 success, -1 failure */ +set(sp, value) +register struct searcher *sp; +of_t value; +{ + register of_t place = sp->place; + register of_t v = value; + + if (sp->aborted) + return(-1); + + if (CANTAG(v) && !conf.olddbz) { + v |= sp->tag | taghere; + if (v != UNBIAS(VACANT)) /* BIAS(v) won't look VACANT */ +#ifdef OVERFLOW + if (v != LONG_MAX) /* and it won't overflow */ +#endif + value = v; + } else if (!conf.olddbz) + conf.ntagless[0]++; + DEBUG(("tagged value is 0x%lx\n", value)); + value = BIAS(value); + value = MAPOUT(value); + + /* If we have the index file in memory, use it */ + if (corepag != NULL && place < conf.tsize) { + corepag[place] = value; + DEBUG(("set: incore\n")); + if (!writethrough) + return(0); + } + + /* seek to spot */ + pagpos = -1; /* invalidate position memory */ + if (fseek(pagf, place * (of_t)SOF, SEEK_SET) != 0) { + DEBUG(("set: seek failed\n")); + sp->aborted = 1; + return(-1); + } + + /* write in data */ + if (fwrite((char *)&value, SOF, 1, pagf) != 1) { + DEBUG(("set: write failed\n")); + sp->aborted = 1; + return(-1); + } + /* fflush improves robustness, and buffer re-use is rare anyway */ + if (fflush(pagf) == EOF) { + DEBUG(("set: fflush failed\n")); + sp->aborted = 1; + return(-1); + } + + DEBUG(("set: succeeded\n")); + return(0); +} + +/* + - mybytemap - determine this machine's byte map + * + * A byte map is an array of ints, sizeof(of_t) of them. The 0th int + * is the byte number of the high-order byte in my of_t, and so forth. + */ +static void +mybytemap(map) +int map[]; /* -> int[SOF] */ +{ + union { + of_t o; + char c[SOF]; + } u; + register int *mp = &map[SOF]; + register int ntodo; + register int i; + + u.o = 1; + for (ntodo = (int)SOF; ntodo > 0; ntodo--) { + for (i = 0; i < SOF; i++) + if (u.c[i] != 0) + break; + if (i == SOF) { + /* trouble -- set it to *something* consistent */ + DEBUG(("mybytemap: nonexistent byte %d!!!\n", ntodo)); + for (i = 0; i < SOF; i++) + map[i] = i; + return; + } + DEBUG(("mybytemap: byte %d\n", i)); + *--mp = i; + while (u.c[i] != 0) + u.o <<= 1; + } +} + +/* + - bytemap - transform an of_t from byte ordering map1 to map2 + */ +static of_t /* transformed result */ +bytemap(ino, map1, map2) +of_t ino; +int *map1; +int *map2; +{ + union oc { + of_t o; + char c[SOF]; + }; + union oc in; + union oc out; + register int i; + + in.o = ino; + for (i = 0; i < SOF; i++) + out.c[map2[i]] = in.c[map1[i]]; + return(out.o); +} + +/* + * This is a simplified version of the pathalias hashing function. + * Thanks to Steve Belovin and Peter Honeyman + * + * hash a string into a long int. 31 bit crc (from andrew appel). + * the crc table is computed at run time by crcinit() -- we could + * precompute, but it takes 1 clock tick on a 750. + * + * This fast table calculation works only if POLY is a prime polynomial + * in the field of integers modulo 2. Since the coefficients of a + * 32-bit polynomial won't fit in a 32-bit word, the high-order bit is + * implicit. IT MUST ALSO BE THE CASE that the coefficients of orders + * 31 down to 25 are zero. Happily, we have candidates, from + * E. J. Watson, "Primitive Polynomials (Mod 2)", Math. Comp. 16 (1962): + * x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + x^0 + * x^31 + x^3 + x^0 + * + * We reverse the bits to get: + * 111101010000000000000000000000001 but drop the last 1 + * f 5 0 0 0 0 0 0 + * 010010000000000000000000000000001 ditto, for 31-bit crc + * 4 8 0 0 0 0 0 0 + */ + +#define POLY 0x48000000L /* 31-bit polynomial (avoids sign problems) */ + +static long CrcTable[128]; + +/* + - crcinit - initialize tables for hash function + */ +static void +crcinit() +{ + register int i, j; + register long sum; + + for (i = 0; i < 128; ++i) { + sum = 0L; + for (j = 7 - 1; j >= 0; --j) + if (i & (1 << j)) + sum ^= POLY >> j; + CrcTable[i] = sum; + } + DEBUG(("crcinit: done\n")); +} + +/* + - hash - Honeyman's nice hashing function + */ +static long +hash(name, size) +register char *name; +register int size; +{ + register long sum = 0L; + + while (size--) { + sum = (sum >> 7) ^ CrcTable[(sum ^ (*name++)) & 0x7f]; + } + DEBUG(("hash: returns (%ld)\n", sum)); + return(sum); +} + +/* + * case-mapping stuff + * + * Borrowed from C News, by permission of the authors. Somewhat modified. + * + * We exploit the fact that we are dealing only with headers here, and + * headers are limited to the ASCII characters by RFC822. It is barely + * possible that we might be dealing with a translation into another + * character set, but in particular it's very unlikely for a header + * character to be outside -128..255. + * + * Life would be a whole lot simpler if tolower() could safely and portably + * be applied to any char. + */ + +#define OFFSET 128 /* avoid trouble with negative chars */ + +/* must call casencmp before invoking TOLOW... */ +#define TOLOW(c) (cmap[(c)+OFFSET]) + +/* ...but the use of it in CISTREQN is safe without the preliminary call (!) */ +/* CISTREQN is an optimised case-insensitive strncmp(a,b,n)==0; n > 0 */ +#define CISTREQN(a, b, n) \ + (TOLOW((a)[0]) == TOLOW((b)[0]) && casencmp(a, b, n) == 0) + +#define MAPSIZE (256+OFFSET) +static char cmap[MAPSIZE]; /* relies on init to '\0' */ +static int mprimed = 0; /* has cmap been set up? */ + +/* + - mapprime - set up case-mapping stuff + */ +static void +mapprime() +{ + register char *lp; + register char *up; + register int c; + register int i; + static char lower[] = "abcdefghijklmnopqrstuvwxyz"; + static char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + for (lp = lower, up = upper; *lp != '\0'; lp++, up++) { + c = *lp; + cmap[c+OFFSET] = c; + cmap[*up+OFFSET] = c; + } + for (i = 0; i < MAPSIZE; i++) + if (cmap[i] == '\0') + cmap[i] = (char)(i-OFFSET); + mprimed = 1; +} + +/* + - casencmp - case-independent strncmp + */ +static int /* < == > 0 */ +casencmp(s1, s2, len) +char *s1; +char *s2; +int len; +{ + register char *p1; + register char *p2; + register int n; + + if (!mprimed) + mapprime(); + + p1 = s1; + p2 = s2; + n = len; + while (--n >= 0 && *p1 != '\0' && TOLOW(*p1) == TOLOW(*p2)) { + p1++; + p2++; + } + if (n < 0) + return(0); + + /* + * The following case analysis is necessary so that characters + * which look negative collate low against normal characters but + * high against the end-of-string NUL. + */ + if (*p1 == '\0' && *p2 == '\0') + return(0); + else if (*p1 == '\0') + return(-1); + else if (*p2 == '\0') + return(1); + else + return(TOLOW(*p1) - TOLOW(*p2)); +} + +/* + - mapcase - do case-mapped copy + */ +static char * /* returns src or dst */ +mapcase(dst, src, siz) +char *dst; /* destination, used only if mapping needed */ +char *src; /* source; src == dst is legal */ +size_t siz; +{ + register char *s; + register char *d; + register char *c; /* case break */ + register char *e; /* end of source */ + + + c = cipoint(src, siz); + if (c == NULL) + return(src); + + if (!mprimed) + mapprime(); + s = src; + e = s + siz; + d = dst; + + while (s < c) + *d++ = *s++; + while (s < e) + *d++ = TOLOW(*s++); + + return(dst); +} + +/* + - cipoint - where in this message-ID does it become case-insensitive? + * + * The RFC822 code is not quite complete. Absolute, total, full RFC822 + * compliance requires a horrible parsing job, because of the arcane + * quoting conventions -- abc"def"ghi is not equivalent to abc"DEF"ghi, + * for example. There are three or four things that might occur in the + * domain part of a message-id that are case-sensitive. They don't seem + * to ever occur in real news, thank Cthulhu. (What? You were expecting + * a merciful and forgiving deity to be invoked in connection with RFC822? + * Forget it; none of them would come near it.) + */ +static char * /* pointer into s, or NULL for "nowhere" */ +cipoint(s, siz) +char *s; +size_t siz; +{ + register char *p; + static char post[] = "postmaster"; + static int plen = sizeof(post)-1; + + switch (conf.casemap) { + case '0': /* unmapped, sensible */ + return(NULL); + break; + case 'C': /* C News, RFC 822 conformant (approx.) */ + p = memchr(s, '@', siz); + if (p == NULL) /* no local/domain split */ + return(NULL); /* assume all local */ + if (p - (s+1) == plen && CISTREQN(s+1, post, plen)) { + /* crazy -- "postmaster" is case-insensitive */ + return(s); + } + return(p); + break; + case '=': /* 2.11, neither sensible nor conformant */ + return(s); /* all case-insensitive */ + break; + } + + DEBUG(("cipoint: unknown case mapping `%c'\n", conf.casemap)); + return(NULL); /* just leave it alone */ +} + +/* + - dbzdebug - control dbz debugging at run time + */ +int /* old value */ +dbzdebug(value) +int value; +{ +#ifdef DBZDEBUG + register int old = debug; + + debug = value; + return(old); +#else + return(-1); +#endif +} --- /dev/null +++ suck-4.3.2/include/dbz.h @@ -0,0 +1,39 @@ +/* for dbm and dbz */ +typedef struct { + char *dptr; + int dsize; +} datum; + +/* standard dbm functions */ +extern int dbminit(); +extern datum fetch(); +extern int store(); +extern int delete(); /* not in dbz */ +extern datum firstkey(); /* not in dbz */ +extern datum nextkey(); /* not in dbz */ +extern int dbmclose(); /* in dbz, but not in old dbm */ + +/* new stuff for dbz */ +extern int dbzdbminit(); +extern datum dbzdbmfetch(); +extern int dbzdbmstore(); +extern int dbzdbmclose(); +extern int dbzfresh(); +extern int dbzagain(); +extern datum dbzfetch(); +extern int dbzstore(); +extern int dbzsync(); +extern long dbzsize(); +extern long dbztagmask(); +extern int dbzincore(); +extern int dbzwritethrough(); +extern void (*dbzfiledesc())(); +extern int dbzcancel(); +extern int dbzdebug(); + +/* + * In principle we could handle unlimited-length keys by operating a chunk + * at a time, but it's not worth it in practice. Setting a nice large + * bound on them simplifies the code and doesn't hurt anything. + */ +#define DBZMAXKEY 255 debian/patches/03_IPv6.diff0000664000000000000000000002216712150346725012554 0ustar --- a/active.c +++ b/active.c @@ -181,7 +181,6 @@ int connect_local(PMaster master) { /* connect to localhost NNTP server */ int fd; - struct hostent *hi; char *inbuf; unsigned int port; @@ -190,7 +189,7 @@ int connect_local(PMaster master) { do_debug("Connecting to %s on port %d\n", master->localhost, port); } - if((fd = connect_to_nntphost(master->localhost, &hi, NULL, port, master->local_ssl, &master->local_ssl_struct)) >= 0) { + if((fd = connect_to_nntphost(master->localhost, NULL, 0, NULL, port, master->local_ssl, &master->local_ssl_struct)) >= 0) { /* get the announcement line */ if(sgetline(fd, &inbuf, master->local_ssl, master->local_ssl_struct) < 0) { close(fd); --- a/both.c +++ b/both.c @@ -112,7 +112,7 @@ char *get_long(char *sp, long *intPtr) { char *retval; if(sp==NULL) { - *intPtr=0; + *intPtr=0; retval = sp; } else { @@ -139,42 +139,36 @@ char *get_long(char *sp, long *intPtr) { } /*---------------------------------------------*/ -struct hostent *get_hostent(const char *host) { - struct in_addr saddr; - int c; - struct hostent *hi = NULL; +struct addrinfo *get_addrinfo(const char *host, const char *sport) { + struct addrinfo hints = { .ai_socktype=SOCK_STREAM, .ai_flags = AI_CANONNAME }; + struct addrinfo * res = NULL; - if(host==NULL) { - error_log(ERRLOG_REPORT,both_phrases[0], NULL); + if(host==NULL) { + error_log(ERRLOG_REPORT,both_phrases[0], NULL); } else { - c=*host; - if(isdigit(c)) { - saddr.s_addr = inet_addr(host); - hi = gethostbyaddr((char *)&saddr,sizeof(struct in_addr),AF_INET); - } - else { - hi = gethostbyname(host); + int st = getaddrinfo(host, sport, &hints, &res); + if (st < 0) { + error_log(ERRLOG_REPORT, "%v1%: %v2%: %v3%\n", host, both_phrases[2], gai_strerror(st), NULL); } } - return hi; + return res; } /*--------------------------------------------*/ -int connect_to_nntphost(const char *host, struct hostent **hi, FILE *msgs, unsigned short int portnr, int do_ssl, void **ssl) { - char *ptr, *realhost; - struct in_addr *aptr; - struct in_addr saddr; - struct sockaddr_in address; +int connect_to_nntphost(const char *host, char * name, size_t namelen, FILE *msgs, unsigned short int portnr, int do_ssl, void **ssl) { + char *realhost; char sport[10]; int sockfd = -1; + struct addrinfo * ai; + char buffer[60]; // if not given by caller. NI_MAXHOST would be better, but that's ok as well. #ifdef HAVE_LIBSSL SSL *ssl_struct = NULL; SSL_CTX *test1 = NULL; - + if(do_ssl == TRUE) { (void) SSL_library_init(); - + struct addrinfo * ai; test1 = SSL_CTX_new(SSLv23_client_method()); if(test1 == NULL) { /* whoops */ @@ -183,13 +177,17 @@ int connect_to_nntphost(const char *host } } #endif + if (!name) { + name = buffer; + namelen = sizeof buffer; + } /* handle host:port type syntax */ realhost = strdup(host); if(realhost == NULL) { MyPerror("out of memory copying host name"); return sockfd; } - ptr = strchr(realhost, ':'); + char * ptr = strchr(realhost, ':'); if(ptr != NULL) { *ptr = '\0'; /* null terminate host name */ portnr = atoi(++ptr); /* get port number */ @@ -200,49 +198,44 @@ int connect_to_nntphost(const char *host sprintf(sport, "%hu", portnr); /* cause print_phrases wants all strings */ print_phrases(msgs, both_phrases[1], sport, NULL); - /* Find the internet address of the NNTP server */ - *hi = get_hostent(realhost); - if(*hi == NULL) { - error_log(ERRLOG_REPORT,"%v1%: ",realhost, NULL); - MyPerror(both_phrases[2]); + /* Find the internet addresses of the NNTP server */ + ai = get_addrinfo(realhost, sport); + if(ai == NULL) { free(realhost); - } + } else { free(realhost); - print_phrases(msgs, both_phrases[3], (*hi)->h_name, NULL); - while((ptr = *((*hi)->h_aliases)) != NULL) { - print_phrases(msgs, both_phrases[4], ptr, NULL ); - (*hi)->h_aliases++; - } - if((*hi)->h_addrtype != AF_INET) { - error_log(ERRLOG_REPORT, both_phrases[5], NULL); - } - else { - while((aptr = (struct in_addr *)*((*hi)->h_addr_list)++) != NULL) { - saddr = *aptr; - print_phrases(msgs, both_phrases[17], inet_ntoa(*aptr), NULL); + struct addrinfo * aii; + print_phrases(msgs, both_phrases[3], ai->ai_canonname, NULL); + for (aii=ai; aii; aii=aii->ai_next) { + if (getnameinfo(aii->ai_addr, aii->ai_addrlen, name, namelen, NULL, 0, NI_NUMERICHOST) < 0) { + name[0] = '\0'; } - /* Create a socket */ - if((sockfd = socket( AF_INET, SOCK_STREAM, SOCKET_PROTOCOL)) == -1) { - MyPerror(both_phrases[6]); + if((sockfd = socket(aii->ai_family, aii->ai_socktype, aii->ai_protocol)) == -1) { + continue; // MyPerror(both_phrases[6]); } - else { - address.sin_family = AF_INET; - address.sin_port = htons(portnr); /* NNTP port */ - address.sin_addr= saddr; - + else { /* Establish a connection */ - if(connect(sockfd, (struct sockaddr *)&address, sizeof address ) == -1) { - MyPerror(both_phrases[7]); + if(connect(sockfd, aii->ai_addr, aii->ai_addrlen ) == -1) { + //MyPerror(both_phrases[7]); close(sockfd); sockfd = -1; + continue; } else { - print_phrases(msgs,both_phrases[8], (*hi)->h_name, NULL); + int st = getnameinfo(aii->ai_addr, aii->ai_addrlen, name, namelen, + NULL, 0, NI_NUMERICHOST); + print_phrases(msgs, both_phrases[8],st == 0 ? name : host, NULL); + if (st != 0) name[0] = '\0'; + break; } } } + freeaddrinfo(ai); + if (sockfd < 0) { + MyPerror(both_phrases[6]); // or 7? + } #ifdef HAVE_LIBSSL if(sockfd > -1 && do_ssl == TRUE) { if((ssl_struct = SSL_new(test1)) == NULL) { @@ -263,7 +256,7 @@ int connect_to_nntphost(const char *host else { *ssl = ssl_struct; } - + } #endif } @@ -910,7 +903,6 @@ void vprint_phrases(FILE *fpout, const c fputs(in[vnr-1], fpout); ptr = pnumber+1; /* advance past var */ } - } } if(varyn == FALSE) { --- a/both.h +++ b/both.h @@ -9,7 +9,7 @@ /* declarations */ int sgetline(int fd, char **sbuf, int, void *); int sputline(int fd, const char *outbuf, int, void *); -int connect_to_nntphost(const char *host, struct hostent **, FILE *, unsigned short int, int, void **); +int connect_to_nntphost(const char *host, char *, size_t, FILE *, unsigned short int, int, void **); void disconnect_from_nntphost(int, int, void **); char *number(char *sp, int *intPtr); char *get_long(char *, long *); --- a/rpost.c +++ b/rpost.c @@ -27,7 +27,7 @@ #ifndef PL_na # define PL_na (na) #endif -#endif /* OLD_PERL */u +#endif /* OLD_PERL */ #endif #ifdef HAVE_DIRENT_H @@ -114,7 +114,6 @@ enum { RETVAL_ERROR = -1, RETVAL_OK, RET int main(int argc, char *argv[], char *env[]) { char *inbuf; int response, retval, loop, fargc, i; - struct hostent *hi; struct stat sbuf; char **args, **fargs; Args myargs; @@ -233,7 +232,7 @@ int main(int argc, char *argv[], char *e do_debug("myargs.debug = TRUE\n"); } - + char hostname[NI_MAXHOST]; /* we processed args okay */ if(myargs.host == NULL) { @@ -241,7 +240,7 @@ int main(int argc, char *argv[], char *e retval = RETVAL_ERROR; } else { - myargs.sockfd = connect_to_nntphost( myargs.host, &hi, myargs.status_fptr, myargs.portnr, myargs.do_ssl, &myargs.ssl_struct); + myargs.sockfd = connect_to_nntphost( myargs.host, hostname, sizeof hostname, myargs.status_fptr, myargs.portnr, myargs.do_ssl, &myargs.ssl_struct); if(myargs.sockfd < 0) { retval = RETVAL_ERROR; } @@ -295,8 +294,8 @@ int main(int argc, char *argv[], char *e /* do one article from stdin */ retval = do_article(&myargs, stdin); } - - print_phrases(myargs.status_fptr, rpost_phrases[4], hi->h_name, NULL); + + print_phrases(myargs.status_fptr, rpost_phrases[4], *hostname ? hostname : "the server", NULL); if(myargs.debug == TRUE) { do_debug("Sending quit"); } --- a/suck.c +++ b/suck.c @@ -665,7 +665,6 @@ int do_connect(PMaster master, int which char *inbuf; int nr, resp, retval = RETVAL_OK; - struct hostent *hi; FILE *fp; @@ -696,7 +695,7 @@ int do_connect(PMaster master, int which } fp = (which_time == CONNECT_FIRST) ? master->msgs : NULL; - master->sockfd = connect_to_nntphost( master->host, &hi, fp, master->portnr, master->do_ssl, &master->ssl_struct); + master->sockfd = connect_to_nntphost( master->host, NULL, 0, fp, master->portnr, master->do_ssl, &master->ssl_struct); if(master->sockfd < 0 ) { retval = RETVAL_ERROR; --- a/testhost.c +++ b/testhost.c @@ -59,7 +59,6 @@ void free_phrases(void); int main(int argc, char *argv[]) { int sockfd, response, loop, cmd, quiet, mode_reader, do_ssl, retval = RETVAL_OK; - struct hostent *hi; struct stat sbuf; unsigned short int portnr; FILE *fptr = stdout; /* used to print output to */ @@ -229,7 +228,7 @@ int main(int argc, char *argv[]) { if(retval == RETVAL_OK) { load_phrases(phrases); /* this is here so everything displays okay */ - sockfd = connect_to_nntphost( host, &hi, (quiet == FALSE)? fptr : NULL, portnr, do_ssl, &ssl_struct); + sockfd = connect_to_nntphost( host, NULL, 0, (quiet == FALSE)? fptr : NULL, portnr, do_ssl, &ssl_struct); if(sockfd < 0 ) { retval = RETVAL_ERROR; } debian/patches/04_suck_confif.diff0000664000000000000000000000334712150347662014262 0ustar --- a/suck_config.h +++ b/suck_config.h @@ -44,7 +44,7 @@ /* as number of seconds before timeout */ /* else, comment it out. If you comment it out, if link goes down */ /* we'll just sit, twiddling our bits, until whenever. */ -#define TIMEOUT 90 +#define TIMEOUT 180 #endif /* HAVE_SELECT */ /* signal which will interrupt us DON'T USE SIGKILL OR SIGSTOP */ @@ -95,8 +95,8 @@ #define N_LMOVE_CONFIG "lmove-config" /* config file for lmove */ #define N_XOVER "suckxover" /* parameter file for which articles NOT to download via xover */ #define N_NODOWNLOAD "sucknodownload" /* file name for message-ids that I never download */ -#define N_PHRASES "/usr/local/lib/suck.phrases" /* default location for phrase file */ -#define HISTORY_FILE "/usr/news/db/history" /* default location for history file */ +#define N_PHRASES "/etc/suck/phrases" /* default location for phrase file */ +#define HISTORY_FILE "/var/lib/news/history" /* default location for history file */ /* TEMP FILES created */ #define N_NEWRC "suck.newrc" @@ -112,7 +112,7 @@ /* Various DIRECTORY PATHS, these can be overriden from command line */ #define N_TMPDIR "." /* location of Temp Files */ -#define N_DATADIR "." /* location of Data Files */ +#define N_DATADIR "/etc/suck" /* location of Data Files */ #define N_MSGDIR "./Msgs" /*location of articles produced by suck, if multifile option selected */ /* Argument substition strings for rpost */ @@ -128,7 +128,7 @@ #define RPOST_FAIL_EXT ".fail" /* RNEWS program called by lpost */ -#define RNEWS "/usr/lib/news/rnews" +#define RNEWS "/usr/lib/news/bin/rnews" /* character used as a comment in sucknewsrc */ #define SUCKNEWSRC_COMMENT_CHAR '#' debian/compat0000644000000000000000000000000211771554421010373 0ustar 9 debian/NEWS0000644000000000000000000000071111751166627007700 0ustar suck (4.3.2-1) unstable; urgency=low get-news has been completely rewritten. While not 100% bug-compatable, it should work compatibly for most installations, and can now be used in situations it couldn't be previously. See the man page. /etc/suck/get-news.conf is now a conffile. You'll need to edit it if you don't want to specify the host on the get-news command line. -- Blars Blarson Wed, 9 Jul 2003 01:30:00 -0800 debian/get-news0000644000000000000000000002172411751166627010664 0ustar #! /usr/bin/perl -w # NOTE: this script needs to be run by the news user. # Debian systems will not allow normal users to run ctlinnd and innxmit # or rnews. # Perl version by Blars Blarson, based on sh version by Christophe Le Bars, # Brian Mays, Tolleff Fog Heen, and others use strict; use File::Copy; use File::Path; # defaults, may be overriden in config file or command line my %var = ( "batchmode" => "-br", "bindir" => "/usr/bin", "etcdir" => "/etc/suck", "logdir" => "/var/log/suck", "newsbin" => "/usr/sbin", "newsspooldir" => "/var/spool/news", "postfilter" => "/usr/lib/suck/put-news", "process" => "gp", "quiet" => 0, "remoteport" => 119, "server" => "localhost", "servtype" => "inn2", "spooldir" => "/var/spool/suck", "statedir" => "/var/lib/suck", "timestamp" => 0, "verbose" => 0, ); my @siteoptions = ( "userid", "password", "suckoptions", "rpostoptions", "remoteport", "postfilter", "process", ); my $site; my $etcdir = "/etc/suck"; my $getnewsconf = "$etcdir/get-news.conf"; my $exit = 0; # read the configuration file open CONF, "<$getnewsconf" or die "Could not open $getnewsconf: $!"; while ($_ = ) { if (/^([a-z0-9\-\_\.]+)\:\s+(.*)$/) { $var{$1} = $2; } else { die "Unknown line in $getnewsconf:\n$_" unless (/^\s*(?:$|\#)/); } } close CONF; my $quiet = $var{'quiet'}; my $verbose = $var{'verbose'}; my $timestamp = $var{'timestamp'}; unless (defined $var{'rnews'}) { if (-x "/usr/lib/news/input/rnews") { $var{'rnews'} = "/usr/lib/news/input/rnews"; } elsif (-x '/usr/bin/rnews') { $var{'rnews'} = '/usr/bin/rnews'; } else { die "rnews not found\n"; } } my $defserver = $var{'remoteserver'}; if (exists $var{"outgoingfile"}) { $site = $var{"outgoingfile"}; } else { $site = $var{"remoteserver"}; } # see if site is on the command line if (scalar(@ARGV) && $ARGV[0] !~ /^-/) { $site = shift @ARGV; $var{"remoteserver"} = $site; } foreach my $opt (@siteoptions) { if (exists $var{"${site}_${opt}"}) { $var{$opt} = $var{"${site}_${opt}"}; } } # process the rest of the command line while ($_ = shift @ARGV) { if (/^-outgoingfile$/) { $site = shift @ARGV; foreach my $opt (@siteoptions) { if (exists $var{"${site}_${opt}"}) { $var{$opt} = $var{"${site}_${opt}"}; } } } elsif (/^-server$/) { $var{"server"} = shift @ARGV; } elsif (/^-get(?:only)?$/) { $var{"process"} = "g"; } elsif (/^-post(?:only)?$/) { $var{"process"} = "p"; } elsif (/^-user(?:id)?$/) { $var{"userid"} = shift @ARGV; } elsif (/^-password$/) { $var{"password"} = shift @ARGV; } elsif (/^-noauth$/) { delete $var{"userid"}; delete $var{"password"}; } elsif (/^-port$/) { $var{"remoteport"} = shift @ARGV; } elsif (/^-q(?:iet)?$/) { $quiet++; } elsif (/^-v(?:erbose)?$/) { $verbose++; } elsif (/^-timestamp$/) { $timestamp++; } elsif (/^-h(?:elp)?$/) { print "Usage: $0 [] [-option parm]...\n\n". " The NNTP server you will connect to.\n". "\n". "Options:\n". " -outgoingfile The file of your remote server\n". " outgoing articles.\n". " (default = the remote server name)\n". " -userid The userid to send to the remote\n". " server.\n". " -password The password to send to the remote\n". " server.\n". " -noauth Do not send userid and password.\n". " (even if they are specified in\n". " ${getnewsconf})\n". " -port Set remote port number.\n". " -server Your local NNTP server.\n". " (default = \"$var{'server'}\")\n". " -q Do not display the BPS and article\n". " count messages during download. \n". " Multiple -q to suppress message\n". " -getonly Only get new messages, do not post\n". " -postonly Only post outgoing messages, do not get\n". " new ones\n". " -timestamp put timestamps in log\n". " -verbose Display more messages about process.\n". " Use multiple times for debugging.\n". "\n"; exit 0; } else { die "Unknown option: $_ (use -h for help)"; } } if ($verbose > 1) { print "Options:\n"; foreach (keys %var) { print "$_: $var{$_}\n"; } print "\n"; } my $authopts = ''; if (exists $var{'userid'}) { $authopts = '-Q'; $ENV{'NNTP_USER'} = $var{'userid'}; $ENV{'NNTP_PASS'} = $var{'password'}; } if ($var{'servtype'} =~ /^inn/) { if (system("$var{'bindir'}/testhost $var{'server'} -s -e") != 0) { die "Bad status for the $var{'server'} local NNTP news server: $?"; } } my $lastdir = "$var{'logdir'}/$var{'remoteserver'}"; if (! -d $lastdir) { die "could not create $lastdir" unless mkdir($lastdir); } sub ts { return "" unless($timestamp); my @now = localtime(); return sprintf("%02d:%02d:%02d ", $now[2], $now[1], $now[0]); } my $getnewslog = "$var{'logdir'}/get-news.log"; open LOG, ">>", $getnewslog or die "Could not open $getnewslog: $!"; print LOG "\n".scalar(localtime())."\n"; if ($var{'process'} =~ /g/) { my $batchfile = "$var{'statedir'}/batch.$var{'remoteserver'}.$$"; my $msgdir = "$var{'spooldir'}/$var{'remoteserver'}"; my $errlog = "$var{'logdir'}/errlog"; my $suffix = ''; my $popt = ''; if($defserver ne $var{'remoteserver'}) { $suffix = ".$var{'remoteserver'}"; $popt = "-p $suffix"; } if($quiet && $var{'suckoptions'} !~ /-q/) { $var{'suckoptions'} .= ' -q'; } print LOG ts()."getnews: download articles\n" unless($quiet > 1); my $suckcmd = "$var{bindir}/suck $var{'remoteserver'} $var{'suckoptions'}" ." $authopts $var{'batchmode'} $batchfile -dt $var{'statedir'}" ." -dm $msgdir -dd $var{'etcdir'} $popt -N $var{'remoteport'}" ." -E $errlog"; print ts()."$suckcmd\n" if($verbose); open SUCK, "-|", $suckcmd or die "Could not start $suckcmd: $!"; while (my $l = ) { print LOG ts().$l; print ts().$l if($verbose); } close SUCK; if ($? == 0 || $? == 256) { print ts()."Downloaded Articles\n" unless($quiet > 1); if (-f "$var{'statedir'}/suck.newrc$suffix") { rename("$var{'etcdir'}/sucknewsrc$suffix", "$var{'etcdir'}/sucknewsrc$suffix.old"); move("$var{'statedir'}/suck.newrc$suffix", "$var{'etcdir'}/sucknewsrc$suffix"); } move("$var{'statedir'}/suck.sorted$suffix",$lastdir) if (-f "$var{'statedir'}/suck.sorted$suffix"); move("$var{'statedir'}/suck.killog$suffix",$lastdir) if (-f "$var{'statedir'}/suck.killog$suffix"); move("$var{'etcdir'}/suckothermsgs$suffix",$lastdir) if (-f "$var{'etcdir'}/suckothermsgs$suffix"); if (-f $batchfile) { my $batchcmd = "NNTPSERVER=$var{'server'} $var{'rnews'} <$batchfile"; print ts()."$batchcmd\n" if ($verbose); if (system($batchcmd)) { print STDERR "Local posting error\n"; $exit = 255; } else { print ts()."Posted Articles Locally\n" unless($quiet > 1); rmtree($msgdir); unlink($batchfile); } } } else { print STDERR "Error getting articles, see $errlog\n"; $exit = 1; } } if (! $exit && $var{'process'} =~ /p/) { my $outgoing = $var{'newsspooldir'}; foreach my $a ('.outgoing', 'out.going', 'outgoing') { if (-d "$outgoing/$a") { $outgoing .= "/$a"; last; } } $outgoing .= "/$site"; my $artdir = $var{'newsspooldir'}; $artdir .= "/articles" if (-d "$artdir/articles"); my $outgoingnew = "${outgoing}.new"; foreach my $o ($outgoingnew, $outgoing) { if (-s $o) { if ($o ne $outgoingnew) { rename($outgoing,$outgoingnew); if ($var{'servtype'} =~ /^inn/) { my $flushcmd = "$var{'newsbin'}/ctlinnd flush $site"; print ts()."$flushcmd\n" if ($verbose); if (system($flushcmd) != 0) { print STDERR "Problem running $flushcmd: $!\n"; } } } my $outfile = "$var{'statedir'}/rpost.$var{'remoteserver'}.$$"; my $postcmd = "$var{'bindir'}/rpost $var{'remoteserver'}" ." -N $var{'remoteport'} $authopts -E $var{'logdir'}/errlog" ." $var{'rpostoptions'} -b $outgoingnew -p $artdir" ." -f $var{'postfilter'} \\\$\\\$o=$outfile" ." \\\$\\\$i $outfile"; print LOG ts()."Posting outgoing articles\n"; print ts()."$postcmd\n" if ($verbose); if (system($postcmd) != 0) { print STDERR "Error remote posting\n"; $exit = 2; last; } else { print ts()."Remotely posted articles\n" unless($quiet > 1); unlink($outfile); unlink($outgoingnew); } } } } print ts()."get-news processing complete\n" unless($quiet > 1); close LOG; exit($exit); debian/copyright0000644000000000000000000000076311751166627011143 0ustar This is the Debian prepackaged version of Small newsfeed from an NNTP server with standard NNTP commands.. It was Debianised by Debian QA Group . Changes were made as follows: Added the get-news script (see manpage). Copyright and licence notice: Suck was written by Tim Smith (unknown address), maintained by Sven Goldt (address unknown) (after March 1995), and Robert A. Yetman (since July 1995). Suck is a public domain software. debian/README.Debian0000644000000000000000000000147711751166627011254 0ustar System administrator may use the get-news script located in /usr/sbin to install a newsfeed : See /etc/suck/get-news.conf and the man page get-news.8 Suck has been compiled with the defaults options except for : Default location of history file : "/var/lib/news/history" (can be overridden from command line) Timeout if no read after 180 seconds. (can be overridden from command line) Default location of data files : "/etc/suck/" (can be overridden from command line) Default location of phrase file : "/etc/suck/phrases" (can be overridden from command line) Compiled with perl and ssl support. Socks support has been removed. The build-dependancies are meant for the autobuilders. Suck works fine with older inn libraries. -- Blars Blarson , Sun Oct 26 09:43:01 2003 debian/manpages0000644000000000000000000000002211751166627010712 0ustar debian/get-news.8 debian/changelog0000644000000000000000000005010512156343140011040 0ustar suck (4.3.2-13) unstable; urgency=low * Don't call dh with '--with quilt' and remove quilt from Build-Depends. -- Christian Marillat Thu, 13 Jun 2013 15:16:40 +0200 suck (4.3.2-12) unstable; urgency=low * Restore a lost patch 04_suck_confif to fix various paths (Closes: #704920). -- Christian Marillat Sun, 26 May 2013 11:04:19 +0200 suck (4.3.2-11) unstable; urgency=low * Add support for IPv6 (Thanks to Thomas Rachel for the patch). * Move to debhelper 9 for hardening flags. -- Christian Marillat Sun, 24 Jun 2012 11:19:03 +0200 suck (4.3.2-10) unstable; urgency=low * Add a su directive in the logrotate file (Closes: #651272) -- Christian Marillat Wed, 07 Dec 2011 11:41:37 +0100 suck (4.3.2-9) unstable; urgency=low * debian/copyright remove references to sucknews.org as this domain name has nothing to do with suck (Closes: #617597). -- Christian Marillat Fri, 18 Mar 2011 07:43:37 +0100 suck (4.3.2-8) unstable; urgency=low * Removed deprecated -H{C,I,O} options (Closes: #612258). -- Christian Marillat Fri, 18 Feb 2011 15:51:11 +0100 suck (4.3.2-7) unstable; urgency=low * debian/control add quilt in Build-Depends. New patch 01_rpost-ssl to add ssl support to rpost (Closes: #501343). * Added libperl-dev in Build-depends. * Fix typo in get-news rpostopts --> rpostoptions (Closes: #605272). * Fix read file configuration with number (Closes: #410372). -- Christian Marillat Mon, 29 Nov 2010 16:52:15 +0100 suck (4.3.2-6) testing-proposed-updates; urgency=low * Upload to testing-proposed-updates because this package has been removed in march before my ITA. Now the package is clean. -- Christian Marillat Sun, 26 Oct 2008 19:23:39 +0100 suck (4.3.2-6) unstable; urgency=low * New maintainer (Closes: #494620) * Quote CFLAGS in make call (Closes: #476056) * Remove libperl-dev from Build-Depends because the configure script doesn't find libperl. This better than enabling libperl because for now suck is working (Closes: #463152) * Call perl with -w in get-news (Closes: #460608) * debian/NEWS.Debian rename file in NEWS and fix bad date format. * Moves to Policy 3.8.0 o Removed debian/conffiles -- Christian Marillat Sat, 16 Aug 2008 09:28:08 +0200 suck (4.3.2-5) unstable; urgency=low * fix rpostoptions in get-news (Closes: #363321) * fix return-code checking with inn in get-news (Closes: #312375) * fix a vs an in package description (Closes: #300064) * standards version 3.7.2 * remove unused templates (Closes: #286065) -- Blars Blarson Sat, 13 May 2006 10:38:48 -0700 suck (4.3.2-4) unstable; urgency=low * fix userid bug in getnews (Closes: #264177) * remove obsolete debconf templates (Closes: #234763) * build-conflict libsocksd-dev -- Blars Blarson Mon, 9 Aug 2004 04:29:19 -0700 suck (4.3.2-3) unstable; urgency=low * Fix path of innctl in get-news so posting works properly from inn * Patches from upstream development - better handle no such article errors (Closes: #197781) -- Blars Blarson Sun, 26 Oct 2003 09:44:35 -0800 suck (4.3.2-2) unstable; urgency=low * Rewrite article-posting code in get-news. Previous version was totally non-functional. (closes: #208831) * Allow quiet, verbose, and timestamp to be set in config file. (closes: #212775) * Ignore suck returning 1 (no articles fetched) in get-news. (closes: #207540) * Split NEWS.Debian into NEWS.Debian and README.Debian. * Policy version 3.6.1 (no changes) -- Blars Blarson Sun, 12 Oct 2003 13:12:13 -0700 suck (4.3.2-1) unstable; urgency=low * new upstream release -- incorporates many Debian changes * total rewrite of get-news - Now supports non-inn2 local servers like cnews - in perl, so recommend perl - fixes broken config parsing (Closes: #162166, #191268) - should be faster (fewer forks, only read config once) - timestamp option (Closes: #172426) - revise get-news man page, actually include it (Closes: #198087) - write errors to stderr (Closes: #198088) - display error if suck has problem (closes #151392) * Update to Debian policy 3.6.0 (no changes) * Build-depend on inn-dev 2.4, so we get the current libraries - Suck should still work with older inn2 with -HO option * /etc/suck/get-news.conf is now a conffile - no longer copy from /usr/share/doc (against policy) - no longer using debconf * only change ownership/permissions of get-news.conf if upgrading from before 4.3.1-1 * Rename README.Debian to NEWS.Debian -- Blars Blarson Wed, 9 Jul 2003 20:01:00 -0800 suck (4.3.1-4) unstable; urgency=low * convert from dh_installmanpages to dh_installman * ssl fix from Uns Lider (Closes: #142794) * make sure to compile with -lssl (Closes: #173282) * Fix FTBFS with new inn2-dev (no more inn/configdata.h) * Rewrite to allow runtime history database format selection. Add libdbz subdir with modified cnews libdbz. See README.Debian. (Closes: #137437, #161048) * remove confict with inn (see above) * build-depend on libperl-dev so perl processing is enabled (Closes: #172908) * Handle SIGINT so database not corrupted (Closes: #145150) * remove build-depend on libsocks4 so socks support is disabled. * Update to Debian policy 3.5.9 (no changes) * minor cleanup for compiler warnings -- Blars Blarson Sat, 22 Mar 2003 19:54:14 -0800 suck (4.3.1-3) unstable; urgency=low * Remember to upload source as well. -- Tollef Fog Heen Fri, 13 Dec 2002 19:00:11 +0100 suck (4.3.1-2) unstable; urgency=low * Give reasonable error rather than segfault if host not specfied to rpost (closes #172131) -- Blars Blarson Fri, 13 Dec 2002 01:23:03 -0800 suck (4.3.1-1) unstable; urgency=medium * Fix ownership/permissions on /etc/suck/getnews.conf (closes #172126) * Change remote host in getnews.conf only if we just install example * New upstream release * Adopting (closes #165123) -- Blars Blarson Mon, 09 Dec 2002 10:49:57 -0800 suck (4.3.0-6) unstable; urgency=low * Change exit -1 in get-news and post-news to more sane values. (closes: #147560) * exit sanely when not being able to open /var/lib/suck/* (closes: #151394) * Fix typos in get-news, namely rpostopstions is now rpostoptions (closes: #161932) * Reorganize the parsing in get-news a bit (closes: #157274) -- Tollef Fog Heen Mon, 23 Sep 2002 02:37:11 +0200 suck (4.3.0-5) unstable; urgency=low * Sigh, forgot to upload source. Again. -- Tollef Fog Heen Mon, 8 Apr 2002 22:48:54 +0200 suck (4.3.0-4) unstable; urgency=low * Sigh, forgot to upload source. -- Tollef Fog Heen Mon, 8 Apr 2002 21:47:51 +0200 suck (4.3.0-3) unstable; urgency=low * moved to main * Add documentation from Marcin Kasperski (closes: #139585) * Fix debconf templates (closes: #138088) * Add support for per-site rpost and suck options and document them in the sample get-news.conf. (Closes: #127321) * Apply patch for allowing "new" port notation (closes: #123207) * Move local posting before remote posting, and don't die on failed postings, though die at the end. (closes: 138006) * Add French templates (closes: #138808), and split the debconf templates to different files. -- Tollef Fog Heen Sun, 7 Apr 2002 03:18:32 +0200 suck (4.3.0-2) unstable; urgency=low * Hopefully fix segfault. (closes: #111029) * Fix SSL option in suck.c (closes: #123206) -- Tollef Fog Heen Thu, 13 Dec 2001 17:23:44 +0100 suck (4.3.0-1) unstable; urgency=low * New upstream release (closes: #121392) * Rebuild with non-broken libsocks4 (closes: #121181) * Move to non-us (since this supports SSL) -- Tollef Fog Heen Wed, 28 Nov 2001 18:06:30 +0100 suck (4.2.5-17) unstable; urgency=low * Second try at eliminating the ugly segfault, now with a modified max Message-ID patch applied. (closes: #111029) -- Tollef Fog Heen Thu, 11 Oct 2001 13:13:43 +0200 suck (4.2.5-16) unstable; urgency=low * Fix segfault by reverting the maximum Message-ID-patch, but bumping the maximum length to 512. (closes: #108181) * Update builddeps, we use dh_installlogrotate, which means that we need debhelper 2.0.103 or newer. * Move /var/state/suck to /var/lib/suck (closes: 108228) * Fix a few sprintfs to snprintfs. * Install samples (closes: 108436) -- Tollef Fog Heen Thu, 9 Aug 2001 21:00:26 +0200 suck (4.2.5-15) unstable; urgency=low * Remove the maximum Message-ID length and make it arbitary. (closes: #107620) -- Tollef Fog Heen Fri, 3 Aug 2001 21:21:47 +0200 suck (4.2.5-14) unstable; urgency=low * remove -x in put-news * Make /etc/news/server a fallback in case we don't have a default news server in /etc/suck/get-news.conf. (closes: #98973) * add rpostoptions to get-news.conf and support it in get-news. (closes: #100341) * add spanish template (closes: #102136) -- Tollef Fog Heen Wed, 25 Jul 2001 19:31:08 +0200 suck (4.2.5-13) unstable; urgency=low * Conflict with inn >> 0.0.0 and inn2 < 2.3.0, this should fix the dependency trouble. (closes: #93927) * possible to control sucking and posting separately. (closes: #90593) * Make -q -q get-news shut completely up. (closes: #91743) * removed call to dh_testversion. -- Tollef Fog Heen Tue, 17 Apr 2001 01:39:04 +0200 suck (4.2.5-12) unstable; urgency=low * Fix up the conflicts line, actually, we depend on inn2 >> 2.3 now. * Fix the permissions of /etc/suck, /var/{spool,log,state}/suck * Rebuild with new libsocks4, which fixes the missing dependency on libsocks4. -- Tollef Fog Heen Thu, 12 Apr 2001 10:37:40 +0200 suck (4.2.5-11) unstable; urgency=low * Fixed put-news so that it now works with inn 2.3 storage api (closes: #81160), but I also had to fix up chkhistory, so we need to conflict with inn2 < 2.3.0 :( . I'd appreciate if somebody knew a way around this, so that we could continue to support inn 1.x and 2.[12].x * removed the suidregister call (which wasn't doing anything anyhow). -- Tollef Fog Heen Wed, 14 Mar 2001 11:30:14 +0100 suck (4.2.5-10) unstable; urgency=low * Fixed the hack which was introduced in the last version, thanks to Marco d'Itri. -- Tollef Fog Heen Mon, 26 Feb 2001 21:02:00 +0100 suck (4.2.5-9) unstable; urgency=low * Added support for multiple password/username combos in /etc/suck/get-news.conf * export NNTP_USER and NNTP_PASS variables in get-news * Add a temporary hack around the fact that rnews in inn and inn2 have different command line options. (closes: #87644) -- Tollef Fog Heen Mon, 26 Feb 2001 15:50:55 +0100 suck (4.2.5-8) unstable; urgency=low * Clean up old NMU fixed bugs (closes: #61142, #62080, #64387, #67602, #67764) * Added example ip-up script (closes: #57511) * cleaned up get-news somewhat, including logging rpost to errorlog instead of stderr. (closes: #73660) * uses rnews instead of innxmit and fix so that the flush is set whether we use rnews or innxmit. (closes: #83727) * put-news had wandered around. Moved to it's proper place again (closes: #86606) * Lots and lots of cleanups in get-news. Tell me what I've broken. :) -- Tollef Fog Heen Sun, 25 Feb 2001 18:54:25 +0100 suck (4.2.5-7) unstable; urgency=low * Fixed up so that we use debhelper the proper way and don't touch conffiles. (closes: #86119) * Added manpage for put-news. -- Tollef Fog Heen Sun, 25 Feb 2001 17:15:02 +0100 suck (4.2.5-6) unstable; urgency=low * Added missing put-news. (closes: #85735) -- Tollef Fog Heen Mon, 12 Feb 2001 23:59:09 +0100 suck (4.2.5-5) unstable; urgency=low * Duh! I should have put the previous missing line in postinst, not postinst.debhelper. Mea Culpa, but this shouldn't haven't been installed into the archive. (closes: #85460, #85454) -- Tollef Fog Heen Sun, 11 Feb 2001 00:22:05 +0100 suck (4.2.5-4) unstable; urgency=low * Fixed a typo in the postinst where the postinst wouldn't run because of a missing '#! /bin/sh'. (closes: #85460, #85454) -- Tollef Fog Heen Sat, 10 Feb 2001 23:24:19 +0100 suck (4.2.5-3) unstable; urgency=low * Adopted the package (closes: #80492) * Use custom options when fetching from all servers (closes: #66608) * Make sure the post-download state files exist, using patch in 76752. (closes: #76752) * Added lmove (closes: #66089) * get-news now puts the authentication stuff in the environment - small patch for suck.c and rpost.c needed, forwarded upstream. (closes: #63917) * Changed from yada to debhelper * Added some README files which weren't included before. * Added Swedish, Norwegian and German translations to the debconf template. (closes: #83401, #83485) -- Tollef Fog Heen Sun, 4 Feb 2001 22:08:47 +0100 suck (4.2.5-2) unstable; urgency=low * Rebuilt with yada 0.9.3. Closes: Bug#81705. * Conforms to Standards version 3.2.1: * Added support for the `debug' build option. -- Matej Vela Thu, 11 Jan 2001 00:36:29 +0100 suck (4.2.5-1) unstable; urgency=low * New upstream release with pristine sources (closes: #67764) * Added note in get-news.conf for inn2 (closes: #62080) * Added some new headers in default put-news filter (closes: #67602, #64387) * Orphaned the package -- Christophe Le Bars Mon, 25 Dec 2000 22:30:22 +0100 suck (4.2.2-4) frozen unstable; urgency=low * Modified put-news script for compatibility with inn2 (closes: #56758) -- Christophe Le Bars Fri, 18 Feb 2000 20:42:57 +0100 suck (4.2.2-3) frozen unstable; urgency=low * Added Build-Depends field * Fixed debconf config (closes: #56220) -- Christophe Le Bars Thu, 27 Jan 2000 23:33:53 +0100 suck (4.2.2-2) frozen unstable; urgency=low * Used better sed command in postinst (closes: #54511) * Patched get-news to support new INN 2 /var/spool/news layout (Lee Maguire) (closes: #55384) * Added debconf support -- Christophe Le Bars Tue, 25 Jan 2000 00:25:58 +0100 suck (4.2.2-1) unstable; urgency=low * New upstream release with pristine sources (closes: #34502, #42286) * Converted package management to YADA * Partially upgraded to standards version 3.0.0: - FHS-compliance, with the notable exception of the /usr/doc/ -> /usr/share/doc/ switch. - savelog -> logrotate switch. * Added a README.Debian (closes: #39169) * Compiled with more standard options (closes: #36269) * get-news fix : post downloaded articles to local server even if upload fail (closes: #34936) -- Christophe Le Bars Tue, 3 Aug 1999 21:31:25 +0200 suck (3.10.1-3) frozen unstable; urgency=medium * Patched get-news to clean batch files (Fixes: Bug#26600) * Patched get-news to keep OUTGOING with inn (Fixes: Bug#28228) * Moved put-news in /usr/lib/suck -- Christophe Le Bars Sat, 5 Dec 1998 20:54:24 +0100 suck (3.10.1-2) frozen unstable; urgency=low * Fixed a syntax typo in get-news (Fixes: Bug#28099) -- Christophe Le Bars Sat, 17 Oct 1998 11:49:17 +0200 suck (3.10.1-1) unstable; urgency=low * New upstream release with pristine sources (Fixes: Bug#27575) * Merged get-news.inn and get-news.cnews * Patched get-news to support passing options to suck (Davide G. M. Salvetti) (Fixes: Bug#27025) * Added cron.weekly /var/log/suck directory test (Fixes: Bug#26054) * Patched get-news to add `date` to suck-status (Fixes: Bug#18861) * Added X-Server-Date in get-news.conf (Fixes: Bug#24552) * Deleted reference to lpost in suck manpage (Fixes: Bug#21735) -- Christophe Le Bars Wed, 14 Oct 1998 23:29:52 +0200 suck (3.9.0-1) unstable; urgency=low * New upstream release with pristine sources -- Christophe Le Bars Sat, 7 Feb 1998 02:45:00 +0100 suck (3.8.0-2) unstable; urgency=low * Modified get-news script to accept -port option (Bug#16358) (Mark Baker patch) * Fixed libc6 Makefile problem (Bug#14065) -- Christophe Le Bars Wed, 28 Jan 1998 21:13:17 +0100 suck (3.8.0-1) unstable; urgency=low * New upstream release with pristine sources * Modified get-news script to accept -q option (Bug#14941) -- Christophe Le Bars Mon, 8 Dec 1997 00:12:35 +0100 suck (3.6.0-1) unstable; urgency=low * New upstream release with pristine sources (Bug#13408) * Build with libc6 -- Christophe Le Bars Sat, 27 Sep 1997 23:18:26 +0200 suck (3.5.2-3) unstable; urgency=low * Fixed get-news manpage section -- Christophe Le Bars Mon, 18 Aug 1997 22:47:57 +0200 suck (3.5.2-2) unstable; urgency=low * Used debian suck_config.h -- Christophe Le Bars Sun, 17 Aug 1997 21:56:59 +0200 suck (3.5.2-1) unstable; urgency=low * New upstream source * Move logs in /var/log/suck (Bug#11055) * Added get-news manpage (Bug#11849) * Fixed postinst sed problem (Bug#11850) -- Christophe Le Bars Sun, 17 Aug 1997 19:02:47 +0200 suck (3.5.1-1) unstable; urgency=low * New upstream source (Bug#10895) * Only suggests news-transport-system (Bug#10549) -- Christophe Le Bars Sun, 29 Jun 1997 22:36:31 +0200 suck (3.4.1-2) frozen unstable; urgency=medium * Fixed put-news script to change only the headers (Bug#9314) * Changed default sed command in get-news.conf (Bug#9313) * Fixed directory for outgoing newsfeeds in get-news.inn (Bug#9312) * Changed timeout value (Bug#8714) -- Christophe Le Bars Sat, 3 May 1997 22:52:46 +0200 suck (3.4.1-1) frozen unstable; urgency=medium * New upstream source (fixes killer bug) (Bug#8453) -- Christophe Le Bars Sun, 6 Apr 1997 16:31:37 +0200 suck (3.4.0-1) unstable; urgency=low * New upstream source * Corrected bad rnews path in get-news.cnews script (Bug#7479) * Modified put-news script to read the sed command in get-news.conf -- Christophe Le Bars Sun, 23 Mar 1997 15:15:15 +0100 suck (3.3.2-1) frozen unstable; urgency=low * New upstream source (bug fixes only release) -- Christophe Le Bars Sat, 23 Nov 1996 16:23:16 +0100 suck (3.3.0-1) unstable; urgency=low * New upstream source * Modified get-news script to accept authinfo options (Brian Mays patch) -- Christophe Le Bars Sat, 26 Oct 1996 15:42:26 +0200 suck (3.2.1-2) unstable; urgency=routine * Fixed /etc/cron.weekly/suck script * Fixed history file path (bug#4670) -- Christophe Le Bars Wed, 2 Oct 1996 21:49:20 +0200 suck (3.2.1-1) unstable; urgency=low * Converted package management files to new Debian-1.2 style * Added postrm purge call * Added weekly logsfiles rotation -- Christophe Le Bars Mon, 30 Sep 1996 00:53:56 +0200 suck (2.6.3-2); urgency=routine * Corrected debian.rules for new naming scheme * Modified get-news script to have multiple site feeds * Deleted section field in debian.control * Support multiple architectures (Bug#3887) * Fixed user and group ownership of some files (bug#3828) * Corrected bad put-news path in get-news script (Bug#3938) * Corrected bad title in /etc/suck/get-news.conf file (Bug#3938) * Provided list of the compiled defaults options (Bug#3938) suck (2.6.3-1); urgency=low * Initial release * Added Debian Linux package maintenance system files * Modified get-news script debian/lintian-overrides0000644000000000000000000000111711751166627012563 0ustar suck: non-standard-dir-perm etc/suck/ 0775 != 0755 suck: non-standard-file-perm etc/suck/get-news.conf 0664 != 0644 suck: non-standard-file-perm etc/suck/suckkillfile 0664 != 0644 suck: non-standard-file-perm etc/suck/sucknewsrc 0664 != 0644 suck: non-standard-dir-perm var/lib/suck/ 0775 != 0755 suck: non-standard-dir-perm var/log/suck/ 0775 != 0755 suck: non-standard-dir-perm var/spool/suck/ 0775 != 0755 suck: manpage-has-errors-from-man usr/share/man/man1/suck.1.gz 192: warning: numeric expression expected (got `s') suck: no-debconf-templates suck: postinst-does-not-load-confmodule debian/ip-up0000644000000000000000000000046411751166627010163 0ustar # !/bin/sh # # /etc/ppp/ip-up.d/suck # script to start getnews at dial up if [ -f /var/lib/suck/status ]; then mv /var/lib/suck/status /var/lib/suck/status.old fi if [ -x /usr/sbin/get-news ]; then su news --command="/usr/sbin/get-news > /var/lib/suck/status" fi Local variables: mode: sh End: debian/dirs0000644000000000000000000000012411751166627010063 0ustar etc etc/suck usr/bin usr/lib/suck usr/sbin var/log/suck var/spool/suck var/lib/suck debian/stamp-patched0000644000000000000000000000000011751166627011645 0ustar debian/config0000644000000000000000000000006011751166627010366 0ustar #! /bin/sh -e . /usr/share/debconf/confmodule debian/suckkillfile0000644000000000000000000000007011751166627011603 0ustar HILINES=10000 #LOWLINES=1 #PATH=yourpathhost #NRGRPS=30 debian/control0000644000000000000000000000206212156343067010600 0ustar Source: suck Section: news Priority: extra Maintainer: Christian Marillat Standards-Version: 3.9.4 Build-Conflicts: libsocksd-dev Build-Depends: debhelper (>= 9), inn2-dev (>= 2.4), libssl-dev, libperl-dev Package: suck Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Recommends: perl Suggests: news-transport-system, news-reader Description: small newsfeed from an NNTP server with standard NNTP commands This package contains software for copying news from an NNTP server to your local machine, and copying replies back up to an NNTP server. . The suck/rpost combination allows you to run your own INN/CNEWS site, controlling where you get your news, and where you post outgoing articles. Suck/rpost use only standard NNTP commands that are used by your favorite news reader (like tin, knews, trn) such as POST and ARTICLE. If you can use tin or knews against an NNTP site, than you can use Suck/Rpost and have multiple site feeds. . NOTE: Suck will not work with obsolete NNTP servers that can't handle the xhdr command. debian/get-news.80000644000000000000000000000551011751166627011025 0ustar .\" $Revision: 2.0 $ .TH GET-NEWS 8 .SH NAME get-news - Debian Suck front end .SH SYNOPSIS .I get-news [ .BI sitename ] [ .BI \-h ] [ .BI \-outgoingfile filename ] [ .BI \-userid userid ] [ .BI \-password password ] [ .BI \-noauth ] [ .BI \-port port ] [ .BI \-server sitename ] [ .BI \-q ] [ .BI \-getonly ] [ .BI \-postonly ] [ .BI \-timestamp ] [ .BI \-verbose ] sitename The name of the site get-news should connect. If this parameter is specified, it will be used for multiple purposes, setting: \- the DNS name of the NNTP host which get-news will connect to download and upload articles \- the suffix for some configuration files get-news will use (sucknewsrc, active-ignore, suckkillfile) \- the news feed name (name of the file in /var/spool/news/outgoing which contain list of the articles to be send) For example, running the command get-news news.provider.site causes the script to contact news.provider.site, send messages listed in /var/spool/news/outgoing/news.provider.site (according to the feed of this name defined in /etc/news/newsfeeds) and use /etc/suck/sucknewsrc.news.provider.site as list of newsgroups, /etc/suck/suckkillfile.news.provider.site as killfile and (in case -A or -AL is specified in get-news.conf) suit newsgroup list to /etc/suck/active-ignore.news.provider.site. When the sitename parameter is missing (like when get-news is run without parameters), get-news uses parameters from get-news.conf (remoteserver to specify the host, outgoingfile to specify the feed) and no-suffix configuration files (sucknewsrc, active-ignore, suckkillfile). \-outgoingfile filename This option tells get-news to use an alternate remote server outgoing articles filename, instead of the default, the remote server name. \-userid userid \-password password These two options let you specify a userid and password, if your NNTP server requires them. \-noauth This option tells get-news to not send userid and password, even if they are specified in /etc/suck/get-news.conf. \-port port This option let you specify a port number, if your NNTP server has a non standard one. \-server sitename This option tells get-news to use sitename as your local NNTP server, instead of the default, localhost. \-q Be quiet. Do not display the BPS and article count messages during download. Multiple \-q's makes get\-news shut up \-getonly Only get new news, don't post anything outgoing. \-postonly Only post outgoing news, don't get anything. \-timestamp Add timestamps to the get-news.log and verbose output. \-verbose Give more messages about what get-news is doing. Specified multiple times, debugging output is enabled. .SH GET-NEWS.CONF .PP Suck looks for a file .I get-news.conf in /etc/suck to initialize some defaults and set some options that are not available on the command line. .SH "SEE ALSO" suck(1), testhost(1), rpost(1), lpost(1). debian/rules0000755000000000000000000000227312156343024010252 0ustar #! /usr/bin/make -f %: dh $@ override_dh_auto_configure: dh_auto_configure -- \ --with-inn-lib="/usr/lib/news $(shell dpkg-buildflags --get LDFLAGS)" \ --with-multi-history override_dh_auto_install: $(MAKE) prefix=$(CURDIR)/debian/suck/usr install override_dh_fixperms: dh_fixperms chown -R news:news debian/suck/etc/suck debian/suck/var/spool/suck debian/suck/var/log/suck debian/suck/var/lib/suck chmod -R g+w debian/suck/etc/suck debian/suck/var/spool/suck debian/suck/var/log/suck debian/suck/var/lib/suck chmod 0644 debian/suck/etc/suck/suckkillfile debian/suck/etc/suck/sucknewsrc debian/suck/etc/suck/get-news.conf chmod 0755 debian/suck/usr/lib/suck/put-news chmod -x debian/suck/usr/share/doc/suck/examples/* override_dh_clean: dh_clean libcnews.a override_dh_installlogrotate: dh_installlogrotate # logroate 3.8+ requires an additional "su" command which is not # backportable, see #640493 if dpkg --compare-versions `apt-cache show logrotate | grep ^Version | cut -f2- -d' '` ge 3.8; then \ echo "Fixing logrotate configuration for logrotate >= 3.8..."; \ sed -i '/^}/ i\ su news news' debian/suck/etc/logrotate.d/*; \ fi override_dh_builddeb: dh_builddeb -- -Zbzip2 debian/postinst0000644000000000000000000000072611751166627011015 0ustar #! /bin/sh -e if dpkg --compare-versions "$2" lt-nl "4.3.1-1" then # fix permissions on get-news.conf chown root:news /etc/suck/get-news.conf chmod 640 /etc/suck/get-news.conf fi # Move /var/state/suck to /var/lib/suck if [ -d /var/state/suck ]; then mv -f /var/state/suck/* /var/lib/suck/ || true rmdir /var/state/suck || true fi # Remove /var/lib/suck/suck.db because of changed on-disk file format. rm -f /var/lib/suck/suck.db #DEBHELPER# debian/install0000644000000000000000000000021611751166627010572 0ustar debian/get-news usr/sbin debian/put-news usr/lib/suck debian/suckkillfile etc/suck debian/get-news.conf etc/suck debian/sucknewsrc etc/suck debian/sucknewsrc0000644000000000000000000000017411751166627011316 0ustar #comp.os.linux.announce -1 #comp.security.announce -1 #gnu.announce -1 news.announce.newusers -1 news.newusers.questions -1 debian/put-news0000644000000000000000000000212111751166627010703 0ustar #! /bin/sh # this is just a simple script to run the one line sed # command to strip off the NNTP Posting Header that # my ISP's newsfeed doesn't like. # this could be written as a one liner # sed -e CMD $1 > $2 COMMAND=$0 ETCDIR=/etc/suck # location of sucknewsrc* and killfile* GETNEWSCONF=${ETCDIR}/get-news.conf # defaults for this script if [ $# -ne 2 ]; then echo echo "Usage `basename $0` infile outfile " echo exit 2 fi SEDCMD=`grep ^sedcmd: ${GETNEWSCONF} \ | awk '{gsub(" ","");print}' | cut -c8-` OUTFILE=$2 INFILE=$1 SM=/usr/lib/news/bin/sm if [ -x ${SM} -o -f ${INFILE} ]; then if [ -x ${SM} ]; then # using inn2.3, we need to use sm, which translates inn 2.3's concept # of an article token into something which we can use. *sigh*. And # the infile isn't really a file, it's a mangled token. Kludge. INFILE=`echo ${INFILE} | sed "s,.*/,,"` ${SM} ${INFILE} | sed "1,/^$/{ ${SEDCMD} }" > ${OUTFILE} else sed "1,/^$/{ ${SEDCMD} }" ${INFILE} > ${OUTFILE} fi if [ $? -ne 0 ]; then echo "Error" exit 255 fi else echo "$1 does not exist" exit 127 fi debian/docs0000644000000000000000000000003711751166627010055 0ustar README README.Gui README.Xover debian/suck.logrotate0000644000000000000000000000030711751166627012071 0ustar /var/log/suck/*log { rotate 2 weekly compress missingok } /var/log/suck/suck-err { rotate 2 weekly compress missingok } /var/log/suck/suck-status { rotate 2 weekly compress missingok }