From: Mark Wooding Date: Tue, 14 Feb 2006 13:41:33 +0000 (+0000) Subject: Import ezmlm 0.53 X-Git-Tag: djb/0.53^0 X-Git-Url: https://git.distorted.org.uk/~mdw/ezmlm/commitdiff_plain/5b62e993b0af39700031c2875d7f6654e6a02850 Import ezmlm 0.53 --- 5b62e993b0af39700031c2875d7f6654e6a02850 diff --git a/BIN b/BIN new file mode 100644 index 0000000..76f0320 --- /dev/null +++ b/BIN @@ -0,0 +1,11 @@ +d:::755::: +c:::755:/:ezmlm-make: +c:::755:/:ezmlm-manage: +c:::755:/:ezmlm-send: +c:::755:/:ezmlm-reject: +c:::755:/:ezmlm-return: +c:::755:/:ezmlm-warn: +c:::755:/:ezmlm-weed: +c:::755:/:ezmlm-list: +c:::755:/:ezmlm-sub: +c:::755:/:ezmlm-unsub: diff --git a/BLURB b/BLURB new file mode 100644 index 0000000..a9ca479 --- /dev/null +++ b/BLURB @@ -0,0 +1,50 @@ +ezmlm is an easy-to-use, high-speed mailing list manager for qmail. + +ezmlm lets users set up their own mailing lists within qmail's address +hierarchy. A user, Joe, types + + ezmlm-make ~/SOS ~/.qmail-sos joe-sos isp.net + +and instantly has a functioning mailing list, joe-sos@isp.net, with all +relevant information stored in a new ~/SOS directory. + +ezmlm sets up joe-sos-subscribe and joe-sos-unsubscribe for automatic +processing of subscription and unsubscription requests. Any message to +joe-sos-subscribe will work; Joe doesn't have to explain any tricky +command formats. ezmlm will send back instructions if a subscriber sends +a message to joe-sos-request or joe-sos-help. + +ezmlm automatically archives new messages. Messages are labelled with +sequence numbers; a subscriber can fetch message 123 by sending mail to +joe-sos-get.123. The archive format supports fast message retrieval even +when there are thousands of messages. + +ezmlm takes advantage of qmail's VERPs to reliably determine the +recipient address and message number for every incoming bounce message. +It waits ten days and then sends the subscriber a list of message +numbers that bounced. If that warning bounces, ezmlm sends a probe; if +the probe bounces, ezmlm automatically removes the subscriber from the +mailing list. + +ezmlm is easy for users to control. Joe can edit ~/SOS/text/* to change +any of the administrative messages sent to subscribers. He can remove +~/SOS/public and ~/SOS/archived to disable automatic subscription and +archiving. He can put his own address into ~/SOS/editor to set up a +moderated mailing list. He can edit ~/SOS/{headeradd,headerremove} to +control outgoing headers. ezmlm has several utilities to manually +inspect and manage mailing lists. + +ezmlm uses Delivered-To to stop forwarding loops, Mailing-List to +protect other mailing lists against false subscription requests, and +real cryptographic cookies to protect normal users against false +subscription requests. ezmlm can also be used for a sublist, +redistributing messages from another list. + +ezmlm is reliable, even in the face of system crashes. It writes each +new subscription and each new message safely to disk before it reports +success to qmail. + +ezmlm doesn't mind huge mailing lists. Lists don't even have to fit into +memory. ezmlm hashes the subscription list into a set of independent +files so that it can handle subscription requests quickly. ezmlm uses +qmail for blazingly fast parallel SMTP deliveries. diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..4badf63 --- /dev/null +++ b/CHANGES @@ -0,0 +1,4 @@ +19970629 ezmlm 0.53, alpha. +19970406 ezmlm 0.52, alpha. +19970222 ezmlm 0.51, alpha. +19970203 ezmlm 0.50, alpha. diff --git a/FILES b/FILES new file mode 100644 index 0000000..d3ae087 --- /dev/null +++ b/FILES @@ -0,0 +1,279 @@ +BLURB +README +INSTALL +TODO +THANKS +CHANGES +FILES +BIN +MAN +VERSION +SYSDEPS +Makefile +ezmlm=0 +ezmlm.5 +ezmlm-make=0 +ezmlm-make.1 +ezmlm-make=x +ezmlm-make.c +ezmlm-send=0 +ezmlm-send.1 +ezmlm-send=x +ezmlm-send.c +ezmlm-reject=0 +ezmlm-reject.1 +ezmlm-reject=x +ezmlm-reject.c +ezmlm-list=0 +ezmlm-list.1 +ezmlm-list=x +ezmlm-list.c +ezmlm-sub=0 +ezmlm-sub.1 +ezmlm-sub=x +ezmlm-sub.c +ezmlm-unsub=0 +ezmlm-unsub.1 +ezmlm-unsub=x +ezmlm-unsub.c +ezmlm-manage=0 +ezmlm-manage.1 +ezmlm-manage=x +ezmlm-manage.c +ezmlm-return=0 +ezmlm-return.1 +ezmlm-return=x +ezmlm-return.c +ezmlm-warn=0 +ezmlm-warn.1 +ezmlm-warn=x +ezmlm-warn.c +ezmlm-weed=0 +ezmlm-weed.1 +ezmlm-weed=x +ezmlm-weed.c +getconf.h +getconf.c +log.h +log.c +issub.h +issub.c +subscribe.h +subscribe.c +cookie.h +cookie.c +auto-str=x +auto-str.c +conf-bin +auto_bin.c.do +auto_bin.h +conf-man +install=x +install.c +setup.do +man.do +it.do +targets.do +default.do +default.a.do +default.o.do +default.0.do +conf-cc +conf-ld +find-systype.sh +make-compile.sh +make-load.sh +make-makelib.sh +trycpp.c +warn-auto.sh +fork.h.do +fork.h1 +fork.h2 +tryvfork.c +wait.3 +wait=0 +wait=l +wait.h +wait_pid.c +trywaitp.c +error.3 +error=0 +error_str.3 +error_str=0 +error_temp.3 +error_temp=0 +error=l +error.h +error.c +error_str.c +substdio.3 +substdio=0 +substdio_copy.3 +substdio_copy=0 +substdio_in.3 +substdio_in=0 +substdio_out.3 +substdio_out=0 +substdio=l +substdio.h +substdio.c +substdi.c +substdo.c +substdio_copy.c +subfd.3 +subfd=0 +subfd.h +subfderr.c +readwrite.h +exit.h +str=l +byte.h +byte_chr.c +byte_copy.c +byte_cr.c +byte_diff.c +byte_rchr.c +byte_zero.c +str.h +str_chr.c +str_cpy.c +str_diff.c +str_diffn.c +str_len.c +str_rchr.c +str_start.c +getopt.3 +getopt=0 +sgetopt.3 +sgetopt=0 +subgetopt.3 +subgetopt=0 +getopt=l +sgetopt.h +sgetopt.c +subgetopt.h +subgetopt.c +strerr=l +strerr.h +strerr.c +strerr_sys.c +strerr_die.c +stralloc=l +gen_alloc.h +gen_allocdefs.h +stralloc.3 +stralloc=0 +stralloc.h +stralloc_eady.c +stralloc_pend.c +stralloc_copy.c +stralloc_opyb.c +stralloc_opys.c +stralloc_cat.c +stralloc_catb.c +stralloc_cats.c +stralloc_arts.c +alloc=0 +alloc.3 +alloc=l +alloc.h +alloc.c +alloc_re.c +open=l +open.h +open_append.c +open_read.c +open_trunc.c +uint32.h.do +uint32.h1 +uint32.h2 +tryulong32.c +case.3 +case=0 +case=l +case.h +case_diffb.c +case_lowerb.c +case_startb.c +fs=l +fmt.h +fmt_str.c +fmt_uint.c +fmt_uint0.c +fmt_ulong.c +scan.h +scan_ulong.c +scan_8long.c +lock=l +hasflock.h.do +lock.h +lock_ex.c +tryflock.c +env.3 +env=0 +env=l +env.h +envread.c +slurpclose.h +slurpclose.c +sig=l +sig.h +sig_catch.c +sig_pipe.c +hassgact.h.do +trysgact.c +datetime.3 +datetime=0 +datetime.h +datetime.c +date822fmt.h +date822fmt.c +now.3 +now=0 +now.h +now.c +quote.h +quote.c +seek=l +seek.h +seek_set.c +conf-qmail +auto_qmail.c.do +auto_qmail.h +qmail.h +qmail.c +direntry.3 +direntry=0 +direntry.h.do +direntry.h1 +direntry.h2 +trydrent.c +getln=0 +getln2=0 +getln=l +getln.3 +getln.h +getln.c +getln2.3 +getln2.c +fd=l +fd_copy=0 +fd_move=0 +fd.h +fd_copy.3 +fd_copy.c +fd_move.3 +fd_move.c +surf=0 +surfpcs=0 +surf=l +surf.3 +surf.h +surf.c +surfpcs.3 +surfpcs.h +surfpcs.c +slurp.h +slurp.c +constmap.h +constmap.c diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..a85e9cb --- /dev/null +++ b/INSTALL @@ -0,0 +1,52 @@ +Like any other piece of software (and information generally), ezmlm +comes with NO WARRANTY. + + +Things you have to decide before starting: + +* Where programs will be installed, normally /usr/local/bin/ezmlm. To +change this directory, edit conf-bin now. + +* Where man pages will be installed, normally /usr/local/man. To change +this directory, edit conf-man now. + +* Where the qmail home directory is, normally /var/qmail. To change this +directory, edit conf-qmail now. + + +How to install: + + 1. Compile the programs: + % make + 2. Format the man pages: + % make man + 3. Install the programs and man pages: + # make setup + + +How to test: + + 4. Make sure ezmlm-make is in your path. Create a mailing list: + % ezmlm-make ~/testlist ~/.qmail-testlist me-testlist host + Replace ``me'' and ``host'' with your e-mail address. + 5. Subscribe yourself to the list manually: + % ezmlm-sub ~/testlist me@host + 6. Send a message to the list: + % echo subject:testing | qmail-inject me-testlist@host + You should receive a copy of the message at me@host. + 7. View the list membership: + % ezmlm-list ~/testlist + You should see just one line, containing your address. + 8. Unsubscribe yourself through e-mail: + % qmail-inject me-testlist-unsubscribe@host < /dev/null + When you receive the confirmation number, reply to complete your + unsubscription. Use ezmlm-list to check that the list is empty. + 9. Retrieve the first message from the archive: + % qmail-inject me-testlist-get.1@host < /dev/null + You should receive a copy of your subject:testing message. + + +That's it! To report success: + % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \ + | mail djb-qst@koobera.math.uic.edu +Replace First M. Last with your name. diff --git a/MAN b/MAN new file mode 100644 index 0000000..df7b2a7 --- /dev/null +++ b/MAN @@ -0,0 +1,27 @@ +d:::755::: +d:::755:/man1:: +d:::755:/man5:: +c:::644:/man5/:ezmlm.5: +c:::644:/man1/:ezmlm-list.1: +c:::644:/man1/:ezmlm-make.1: +c:::644:/man1/:ezmlm-manage.1: +c:::644:/man1/:ezmlm-reject.1: +c:::644:/man1/:ezmlm-return.1: +c:::644:/man1/:ezmlm-send.1: +c:::644:/man1/:ezmlm-sub.1: +c:::644:/man1/:ezmlm-unsub.1: +c:::644:/man1/:ezmlm-warn.1: +c:::644:/man1/:ezmlm-weed.1: +d:::755:/cat1:: +d:::755:/cat5:: +c:::644:/cat5/:ezmlm.0: +c:::644:/cat1/:ezmlm-list.0: +c:::644:/cat1/:ezmlm-make.0: +c:::644:/cat1/:ezmlm-manage.0: +c:::644:/cat1/:ezmlm-reject.0: +c:::644:/cat1/:ezmlm-return.0: +c:::644:/cat1/:ezmlm-send.0: +c:::644:/cat1/:ezmlm-sub.0: +c:::644:/cat1/:ezmlm-unsub.0: +c:::644:/cat1/:ezmlm-warn.0: +c:::644:/cat1/:ezmlm-weed.0: diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..111a542 --- /dev/null +++ b/Makefile @@ -0,0 +1,909 @@ +SHELL=/bin/sh + +default: it + +alloc.0: \ +alloc.3 + nroff -man alloc.3 > alloc.0 + +alloc.a: \ +makelib alloc.o alloc_re.o + ./makelib alloc.a alloc.o alloc_re.o + +alloc.o: \ +compile alloc.c alloc.h alloc.c error.h alloc.c + ./compile alloc.c + +alloc_re.o: \ +compile alloc_re.c alloc.h alloc_re.c byte.h alloc_re.c + ./compile alloc_re.c + +auto-ccld.sh: \ +conf-cc conf-ld warn-auto.sh + ( cat warn-auto.sh; \ + echo CC=\'`head -1 conf-cc`\'; \ + echo LD=\'`head -1 conf-ld`\' \ + ) > auto-ccld.sh + +auto-str: \ +load auto-str.o substdio.a error.a str.a + ./load auto-str substdio.a error.a str.a + +auto-str.o: \ +compile auto-str.c substdio.h auto-str.c readwrite.h auto-str.c \ +exit.h auto-str.c + ./compile auto-str.c + +auto_bin.c: \ +auto-str conf-bin + ./auto-str auto_bin `head -1 conf-bin` > auto_bin.c + +auto_bin.o: \ +compile auto_bin.c + ./compile auto_bin.c + +auto_qmail.c: \ +auto-str conf-qmail + ./auto-str auto_qmail `head -1 conf-qmail` > auto_qmail.c + +auto_qmail.o: \ +compile auto_qmail.c + ./compile auto_qmail.c + +byte_chr.o: \ +compile byte_chr.c byte.h byte_chr.c + ./compile byte_chr.c + +byte_copy.o: \ +compile byte_copy.c byte.h byte_copy.c + ./compile byte_copy.c + +byte_cr.o: \ +compile byte_cr.c byte.h byte_cr.c + ./compile byte_cr.c + +byte_diff.o: \ +compile byte_diff.c byte.h byte_diff.c + ./compile byte_diff.c + +byte_rchr.o: \ +compile byte_rchr.c byte.h byte_rchr.c + ./compile byte_rchr.c + +byte_zero.o: \ +compile byte_zero.c byte.h byte_zero.c + ./compile byte_zero.c + +case.0: \ +case.3 + nroff -man case.3 > case.0 + +case.a: \ +makelib case_diffb.o case_lowerb.o case_startb.o + ./makelib case.a case_diffb.o case_lowerb.o case_startb.o + +case_diffb.o: \ +compile case_diffb.c case.h case_diffb.c + ./compile case_diffb.c + +case_lowerb.o: \ +compile case_lowerb.c case.h case_lowerb.c + ./compile case_lowerb.c + +case_startb.o: \ +compile case_startb.c case.h case_startb.c + ./compile case_startb.c + +compile: \ +make-compile warn-auto.sh systype + ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \ + compile + chmod 755 compile + +constmap.o: \ +compile constmap.c constmap.h constmap.c alloc.h constmap.c case.h \ +constmap.c + ./compile constmap.c + +cookie.o: \ +compile cookie.c cookie.h cookie.c str.h cookie.c uint32.h cookie.c \ +surfpcs.h uint32.h surfpcs.h cookie.c + ./compile cookie.c + +date822fmt.o: \ +compile date822fmt.c datetime.h date822fmt.c fmt.h date822fmt.c \ +date822fmt.h date822fmt.c + ./compile date822fmt.c + +datetime.0: \ +datetime.3 + nroff -man datetime.3 > datetime.0 + +datetime.o: \ +compile datetime.c datetime.h datetime.c + ./compile datetime.c + +direntry.0: \ +direntry.3 + nroff -man direntry.3 > direntry.0 + +direntry.h: \ +compile trydrent.c direntry.h1 direntry.h2 + ( ./compile trydrent.c >/dev/null 2>&1 \ + && cat direntry.h2 || cat direntry.h1 ) > direntry.h + rm -f trydrent.o + +env.0: \ +env.3 + nroff -man env.3 > env.0 + +env.a: \ +makelib envread.o + ./makelib env.a envread.o + +envread.o: \ +compile envread.c env.h envread.c str.h envread.c + ./compile envread.c + +error.0: \ +error.3 + nroff -man error.3 > error.0 + +error.a: \ +makelib error.o error_str.o + ./makelib error.a error.o error_str.o + +error.o: \ +compile error.c error.c error.h error.c + ./compile error.c + +error_str.0: \ +error_str.3 + nroff -man error_str.3 > error_str.0 + +error_str.o: \ +compile error_str.c error_str.c error.h error_str.c + ./compile error_str.c + +error_temp.0: \ +error_temp.3 + nroff -man error_temp.3 > error_temp.0 + +ezmlm-list: \ +load ezmlm-list.o strerr.a getln.a substdio.a stralloc.a alloc.a \ +error.a open.a str.a + ./load ezmlm-list strerr.a getln.a substdio.a stralloc.a \ + alloc.a error.a open.a str.a + +ezmlm-list.0: \ +ezmlm-list.1 + nroff -man ezmlm-list.1 > ezmlm-list.0 + +ezmlm-list.o: \ +compile ezmlm-list.c stralloc.h gen_alloc.h stralloc.h ezmlm-list.c \ +substdio.h ezmlm-list.c getln.h ezmlm-list.c strerr.h ezmlm-list.c \ +error.h ezmlm-list.c readwrite.h ezmlm-list.c exit.h ezmlm-list.c \ +open.h ezmlm-list.c + ./compile ezmlm-list.c + +ezmlm-make: \ +load ezmlm-make.o auto_bin.o open.a getopt.a substdio.a strerr.a \ +stralloc.a alloc.a error.a str.a + ./load ezmlm-make auto_bin.o open.a getopt.a substdio.a \ + strerr.a stralloc.a alloc.a error.a str.a + +ezmlm-make.0: \ +ezmlm-make.1 + nroff -man ezmlm-make.1 > ezmlm-make.0 + +ezmlm-make.o: \ +compile ezmlm-make.c ezmlm-make.c ezmlm-make.c sgetopt.h subgetopt.h \ +sgetopt.h ezmlm-make.c stralloc.h gen_alloc.h stralloc.h ezmlm-make.c \ +strerr.h ezmlm-make.c exit.h ezmlm-make.c readwrite.h ezmlm-make.c \ +open.h ezmlm-make.c substdio.h ezmlm-make.c str.h ezmlm-make.c \ +auto_bin.h ezmlm-make.c ezmlm-make.c ezmlm-make.c ezmlm-make.c \ +ezmlm-make.c + ./compile ezmlm-make.c + +ezmlm-manage: \ +load ezmlm-manage.o auto_qmail.o getconf.o subscribe.o log.o cookie.o \ +now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \ +surf.a getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a \ +error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a + ./load ezmlm-manage auto_qmail.o getconf.o subscribe.o \ + log.o cookie.o now.o datetime.o date822fmt.o slurpclose.o \ + slurp.o qmail.o quote.o surf.a getln.a env.a sig.a strerr.a \ + substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \ + open.a seek.a wait.a lock.a fd.a + +ezmlm-manage.0: \ +ezmlm-manage.1 + nroff -man ezmlm-manage.1 > ezmlm-manage.0 + +ezmlm-manage.o: \ +compile ezmlm-manage.c ezmlm-manage.c ezmlm-manage.c error.h \ +ezmlm-manage.c stralloc.h gen_alloc.h stralloc.h ezmlm-manage.c str.h \ +ezmlm-manage.c env.h ezmlm-manage.c sig.h ezmlm-manage.c slurp.h \ +ezmlm-manage.c getconf.h ezmlm-manage.c strerr.h ezmlm-manage.c \ +byte.h ezmlm-manage.c getln.h ezmlm-manage.c case.h ezmlm-manage.c \ +qmail.h substdio.h qmail.h ezmlm-manage.c substdio.h substdio.h \ +ezmlm-manage.c readwrite.h ezmlm-manage.c seek.h ezmlm-manage.c \ +quote.h ezmlm-manage.c datetime.h ezmlm-manage.c now.h datetime.h \ +datetime.h now.h ezmlm-manage.c date822fmt.h ezmlm-manage.c fmt.h \ +ezmlm-manage.c subscribe.h strerr.h strerr.h subscribe.h \ +ezmlm-manage.c cookie.h ezmlm-manage.c + ./compile ezmlm-manage.c + +ezmlm-reject: \ +load ezmlm-reject.o getln.a strerr.a substdio.a error.a stralloc.a \ +alloc.a str.a getopt.a case.a + ./load ezmlm-reject getln.a strerr.a substdio.a error.a \ + stralloc.a alloc.a str.a getopt.a case.a + +ezmlm-reject.0: \ +ezmlm-reject.1 + nroff -man ezmlm-reject.1 > ezmlm-reject.0 + +ezmlm-reject.o: \ +compile ezmlm-reject.c strerr.h ezmlm-reject.c substdio.h \ +ezmlm-reject.c readwrite.h ezmlm-reject.c stralloc.h gen_alloc.h \ +stralloc.h ezmlm-reject.c getln.h ezmlm-reject.c sgetopt.h \ +subgetopt.h sgetopt.h ezmlm-reject.c + ./compile ezmlm-reject.c + +ezmlm-return: \ +load ezmlm-return.o quote.o getconf.o issub.o subscribe.o log.o \ +slurpclose.o slurp.o now.o cookie.o surf.a lock.a env.a sig.a \ +strerr.a getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a \ +case.a open.a + ./load ezmlm-return quote.o getconf.o issub.o subscribe.o \ + log.o slurpclose.o slurp.o now.o cookie.o surf.a lock.a \ + env.a sig.a strerr.a getln.a substdio.a stralloc.a alloc.a \ + error.a str.a fs.a case.a open.a + +ezmlm-return.0: \ +ezmlm-return.1 + nroff -man ezmlm-return.1 > ezmlm-return.0 + +ezmlm-return.o: \ +compile ezmlm-return.c stralloc.h gen_alloc.h stralloc.h \ +ezmlm-return.c str.h ezmlm-return.c env.h ezmlm-return.c sig.h \ +ezmlm-return.c slurp.h ezmlm-return.c getconf.h ezmlm-return.c \ +strerr.h ezmlm-return.c byte.h ezmlm-return.c case.h ezmlm-return.c \ +getln.h ezmlm-return.c substdio.h ezmlm-return.c error.h \ +ezmlm-return.c quote.h ezmlm-return.c readwrite.h ezmlm-return.c \ +fmt.h ezmlm-return.c now.h datetime.h now.h ezmlm-return.c cookie.h \ +ezmlm-return.c subscribe.h strerr.h strerr.h subscribe.h \ +ezmlm-return.c issub.h strerr.h strerr.h issub.h ezmlm-return.c + ./compile ezmlm-return.c + +ezmlm-send: \ +load ezmlm-send.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \ +slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a \ +substdio.a stralloc.a alloc.a error.a str.a fd.a case.a fs.a + ./load ezmlm-send auto_qmail.o getconf.o qmail.o \ + constmap.o slurp.o slurpclose.o wait.a getln.a strerr.a \ + sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a \ + error.a str.a fd.a case.a fs.a + +ezmlm-send.0: \ +ezmlm-send.1 + nroff -man ezmlm-send.1 > ezmlm-send.0 + +ezmlm-send.o: \ +compile ezmlm-send.c stralloc.h gen_alloc.h stralloc.h ezmlm-send.c \ +subfd.h substdio.h subfd.h ezmlm-send.c strerr.h ezmlm-send.c error.h \ +ezmlm-send.c qmail.h substdio.h substdio.h qmail.h ezmlm-send.c env.h \ +ezmlm-send.c lock.h ezmlm-send.c sig.h ezmlm-send.c open.h \ +ezmlm-send.c getln.h ezmlm-send.c case.h ezmlm-send.c scan.h \ +ezmlm-send.c str.h ezmlm-send.c fmt.h ezmlm-send.c readwrite.h \ +ezmlm-send.c exit.h ezmlm-send.c substdio.h substdio.h ezmlm-send.c \ +getconf.h ezmlm-send.c constmap.h ezmlm-send.c + ./compile ezmlm-send.c + +ezmlm-sub: \ +load ezmlm-sub.o subscribe.o log.o now.o fs.a strerr.a getln.a \ +substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a + ./load ezmlm-sub subscribe.o log.o now.o fs.a strerr.a \ + getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \ + open.a lock.a + +ezmlm-sub.0: \ +ezmlm-sub.1 + nroff -man ezmlm-sub.1 > ezmlm-sub.0 + +ezmlm-sub.o: \ +compile ezmlm-sub.c strerr.h ezmlm-sub.c subscribe.h strerr.h \ +strerr.h subscribe.h ezmlm-sub.c log.h ezmlm-sub.c + ./compile ezmlm-sub.c + +ezmlm-unsub: \ +load ezmlm-unsub.o subscribe.o log.o now.o fs.a strerr.a getln.a \ +substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a + ./load ezmlm-unsub subscribe.o log.o now.o fs.a strerr.a \ + getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \ + open.a lock.a + +ezmlm-unsub.0: \ +ezmlm-unsub.1 + nroff -man ezmlm-unsub.1 > ezmlm-unsub.0 + +ezmlm-unsub.o: \ +compile ezmlm-unsub.c strerr.h ezmlm-unsub.c subscribe.h strerr.h \ +strerr.h subscribe.h ezmlm-unsub.c log.h ezmlm-unsub.c + ./compile ezmlm-unsub.c + +ezmlm-warn: \ +load ezmlm-warn.o auto_qmail.o getconf.o cookie.o issub.o now.o \ +slurpclose.o slurp.o quote.o datetime.o date822fmt.o qmail.o surf.a \ +case.a strerr.a sig.a getln.a substdio.a stralloc.a alloc.a error.a \ +open.a lock.a str.a fs.a fd.a wait.a + ./load ezmlm-warn auto_qmail.o getconf.o cookie.o issub.o \ + now.o slurpclose.o slurp.o quote.o datetime.o date822fmt.o \ + qmail.o surf.a case.a strerr.a sig.a getln.a substdio.a \ + stralloc.a alloc.a error.a open.a lock.a str.a fs.a fd.a \ + wait.a + +ezmlm-warn.0: \ +ezmlm-warn.1 + nroff -man ezmlm-warn.1 > ezmlm-warn.0 + +ezmlm-warn.o: \ +compile ezmlm-warn.c ezmlm-warn.c ezmlm-warn.c direntry.h direntry.h \ +direntry.h ezmlm-warn.c readwrite.h ezmlm-warn.c getln.h ezmlm-warn.c \ +substdio.h ezmlm-warn.c stralloc.h gen_alloc.h stralloc.h \ +ezmlm-warn.c slurp.h ezmlm-warn.c getconf.h ezmlm-warn.c byte.h \ +ezmlm-warn.c error.h ezmlm-warn.c str.h ezmlm-warn.c strerr.h \ +ezmlm-warn.c sig.h ezmlm-warn.c now.h datetime.h now.h ezmlm-warn.c \ +datetime.h datetime.h ezmlm-warn.c date822fmt.h ezmlm-warn.c fmt.h \ +ezmlm-warn.c cookie.h ezmlm-warn.c qmail.h substdio.h substdio.h \ +qmail.h ezmlm-warn.c + ./compile ezmlm-warn.c + +ezmlm-weed: \ +load ezmlm-weed.o getln.a strerr.a substdio.a error.a stralloc.a \ +alloc.a str.a + ./load ezmlm-weed getln.a strerr.a substdio.a error.a \ + stralloc.a alloc.a str.a + +ezmlm-weed.0: \ +ezmlm-weed.1 + nroff -man ezmlm-weed.1 > ezmlm-weed.0 + +ezmlm-weed.o: \ +compile ezmlm-weed.c stralloc.h gen_alloc.h stralloc.h ezmlm-weed.c \ +str.h ezmlm-weed.c byte.h ezmlm-weed.c readwrite.h ezmlm-weed.c \ +substdio.h ezmlm-weed.c getln.h ezmlm-weed.c strerr.h ezmlm-weed.c + ./compile ezmlm-weed.c + +ezmlm.0: \ +ezmlm.5 + nroff -man ezmlm.5 > ezmlm.0 + +fd.a: \ +makelib fd_copy.o fd_move.o + ./makelib fd.a fd_copy.o fd_move.o + +fd_copy.0: \ +fd_copy.3 + nroff -man fd_copy.3 > fd_copy.0 + +fd_copy.o: \ +compile fd_copy.c fd_copy.c fd.h fd_copy.c + ./compile fd_copy.c + +fd_move.0: \ +fd_move.3 + nroff -man fd_move.3 > fd_move.0 + +fd_move.o: \ +compile fd_move.c fd.h fd_move.c + ./compile fd_move.c + +find-systype: \ +find-systype.sh auto-ccld.sh + cat auto-ccld.sh find-systype.sh > find-systype + chmod 755 find-systype + +fmt_str.o: \ +compile fmt_str.c fmt.h fmt_str.c + ./compile fmt_str.c + +fmt_uint.o: \ +compile fmt_uint.c fmt.h fmt_uint.c + ./compile fmt_uint.c + +fmt_uint0.o: \ +compile fmt_uint0.c fmt.h fmt_uint0.c + ./compile fmt_uint0.c + +fmt_ulong.o: \ +compile fmt_ulong.c fmt.h fmt_ulong.c + ./compile fmt_ulong.c + +fork.h: \ +compile load tryvfork.c fork.h1 fork.h2 + ( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null \ + 2>&1 \ + && cat fork.h2 || cat fork.h1 ) > fork.h + rm -f tryvfork.o tryvfork + +fs.a: \ +makelib fmt_str.o fmt_uint.o fmt_uint0.o fmt_ulong.o scan_ulong.o \ +scan_8long.o + ./makelib fs.a fmt_str.o fmt_uint.o fmt_uint0.o \ + fmt_ulong.o scan_ulong.o scan_8long.o + +getconf.o: \ +compile getconf.c stralloc.h gen_alloc.h stralloc.h getconf.c slurp.h \ +getconf.c strerr.h getconf.c getconf.h getconf.c + ./compile getconf.c + +getln.0: \ +getln.3 + nroff -man getln.3 > getln.0 + +getln.a: \ +makelib getln.o getln2.o + ./makelib getln.a getln.o getln2.o + +getln.o: \ +compile getln.c substdio.h getln.c byte.h getln.c stralloc.h \ +gen_alloc.h stralloc.h getln.c getln.h getln.c + ./compile getln.c + +getln2.0: \ +getln2.3 + nroff -man getln2.3 > getln2.0 + +getln2.o: \ +compile getln2.c substdio.h getln2.c stralloc.h gen_alloc.h \ +stralloc.h getln2.c byte.h getln2.c getln.h getln2.c + ./compile getln2.c + +getopt.0: \ +getopt.3 + nroff -man getopt.3 > getopt.0 + +getopt.a: \ +makelib subgetopt.o sgetopt.o + ./makelib getopt.a subgetopt.o sgetopt.o + +hasflock.h: \ +tryflock.c compile load + ( ( ./compile tryflock.c && ./load tryflock ) >/dev/null \ + 2>&1 \ + && echo \#define HASFLOCK 1 || exit 0 ) > hasflock.h + rm -f tryflock.o tryflock + +hassgact.h: \ +trysgact.c compile load + ( ( ./compile trysgact.c && ./load trysgact ) >/dev/null \ + 2>&1 \ + && echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h + rm -f trysgact.o trysgact + +install: \ +load install.o getln.a strerr.a substdio.a stralloc.a alloc.a open.a \ +error.a str.a fs.a + ./load install getln.a strerr.a substdio.a stralloc.a \ + alloc.a open.a error.a str.a fs.a + +install.o: \ +compile install.c substdio.h install.c stralloc.h gen_alloc.h \ +stralloc.h install.c getln.h install.c readwrite.h install.c exit.h \ +install.c open.h install.c error.h install.c strerr.h install.c \ +byte.h install.c + ./compile install.c + +issub.o: \ +compile issub.c stralloc.h gen_alloc.h stralloc.h issub.c getln.h \ +issub.c readwrite.h issub.c substdio.h issub.c open.h issub.c byte.h \ +issub.c case.h issub.c lock.h issub.c error.h issub.c issub.h \ +strerr.h issub.h issub.c uint32.h issub.c + ./compile issub.c + +it: \ +ezmlm-make ezmlm-manage ezmlm-send ezmlm-reject ezmlm-return \ +ezmlm-warn ezmlm-weed ezmlm-list ezmlm-sub ezmlm-unsub + +load: \ +make-load warn-auto.sh systype + ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load + chmod 755 load + +lock.a: \ +makelib lock_ex.o + ./makelib lock.a lock_ex.o + +lock_ex.o: \ +compile lock_ex.c lock_ex.c lock_ex.c lock_ex.c hasflock.h lock_ex.c \ +lock.h lock_ex.c + ./compile lock_ex.c + +log.o: \ +compile log.c substdio.h log.c readwrite.h log.c stralloc.h \ +gen_alloc.h stralloc.h log.c log.h log.c now.h datetime.h now.h log.c \ +fmt.h log.c open.h log.c + ./compile log.c + +make-compile: \ +make-compile.sh auto-ccld.sh + cat auto-ccld.sh make-compile.sh > make-compile + chmod 755 make-compile + +make-load: \ +make-load.sh auto-ccld.sh + cat auto-ccld.sh make-load.sh > make-load + chmod 755 make-load + +make-makelib: \ +make-makelib.sh auto-ccld.sh + cat auto-ccld.sh make-makelib.sh > make-makelib + chmod 755 make-makelib + +makelib: \ +make-makelib warn-auto.sh systype + ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \ + makelib + chmod 755 makelib + +man: \ +ezmlm.0 ezmlm-make.0 ezmlm-manage.0 ezmlm-send.0 ezmlm-reject.0 \ +ezmlm-return.0 ezmlm-warn.0 ezmlm-weed.0 ezmlm-list.0 ezmlm-sub.0 \ +ezmlm-unsub.0 alloc.0 case.0 datetime.0 direntry.0 env.0 error.0 \ +error_str.0 error_temp.0 ezmlm.0 fd_copy.0 fd_move.0 getln.0 getln2.0 \ +getopt.0 now.0 sgetopt.0 stralloc.0 subfd.0 subgetopt.0 substdio.0 \ +substdio_copy.0 substdio_in.0 substdio_out.0 surf.0 surfpcs.0 wait.0 + +now.0: \ +now.3 + nroff -man now.3 > now.0 + +now.o: \ +compile now.c now.c datetime.h now.c now.h datetime.h datetime.h \ +now.h now.c + ./compile now.c + +open.a: \ +makelib open_append.o open_read.o open_trunc.o + ./makelib open.a open_append.o open_read.o open_trunc.o + +open_append.o: \ +compile open_append.c open_append.c open_append.c open.h \ +open_append.c + ./compile open_append.c + +open_read.o: \ +compile open_read.c open_read.c open_read.c open.h open_read.c + ./compile open_read.c + +open_trunc.o: \ +compile open_trunc.c open_trunc.c open_trunc.c open.h open_trunc.c + ./compile open_trunc.c + +qmail.o: \ +compile qmail.c substdio.h qmail.c readwrite.h qmail.c wait.h qmail.c \ +exit.h qmail.c fork.h qmail.c fd.h qmail.c qmail.h substdio.h \ +substdio.h qmail.h qmail.c auto_qmail.h qmail.c + ./compile qmail.c + +quote.o: \ +compile quote.c stralloc.h gen_alloc.h stralloc.h quote.c str.h \ +quote.c quote.h quote.c + ./compile quote.c + +scan_8long.o: \ +compile scan_8long.c scan.h scan_8long.c + ./compile scan_8long.c + +scan_ulong.o: \ +compile scan_ulong.c scan.h scan_ulong.c + ./compile scan_ulong.c + +seek.a: \ +makelib seek_set.o + ./makelib seek.a seek_set.o + +seek_set.o: \ +compile seek_set.c seek_set.c seek.h seek_set.c + ./compile seek_set.c + +setup: \ +it man install conf-bin conf-man + ./install "`head -1 conf-bin`" < BIN + ./install "`head -1 conf-man`" < MAN + +sgetopt.0: \ +sgetopt.3 + nroff -man sgetopt.3 > sgetopt.0 + +sgetopt.o: \ +compile sgetopt.c substdio.h sgetopt.c subfd.h substdio.h substdio.h \ +subfd.h sgetopt.c sgetopt.h sgetopt.h subgetopt.h sgetopt.h sgetopt.c \ +subgetopt.h subgetopt.h sgetopt.c + ./compile sgetopt.c + +shar: \ +FILES BLURB README INSTALL TODO THANKS CHANGES FILES BIN MAN VERSION \ +SYSDEPS Makefile ezmlm.5 ezmlm-make.1 ezmlm-make.c ezmlm-send.1 \ +ezmlm-send.c ezmlm-reject.1 ezmlm-reject.c ezmlm-list.1 ezmlm-list.c \ +ezmlm-sub.1 ezmlm-sub.c ezmlm-unsub.1 ezmlm-unsub.c ezmlm-manage.1 \ +ezmlm-manage.c ezmlm-return.1 ezmlm-return.c ezmlm-warn.1 \ +ezmlm-warn.c ezmlm-weed.1 ezmlm-weed.c getconf.h getconf.c log.h \ +log.c issub.h issub.c subscribe.h subscribe.c cookie.h cookie.c \ +auto-str.c conf-bin auto_bin.h conf-man install.c conf-cc conf-ld \ +find-systype.sh make-compile.sh make-load.sh make-makelib.sh trycpp.c \ +warn-auto.sh fork.h1 fork.h2 tryvfork.c wait.3 wait.h wait_pid.c \ +trywaitp.c error.3 error_str.3 error_temp.3 error.h error.c \ +error_str.c substdio.3 substdio_copy.3 substdio_in.3 substdio_out.3 \ +substdio.h substdio.c substdi.c substdo.c substdio_copy.c subfd.3 \ +subfd.h subfderr.c readwrite.h exit.h byte.h byte_chr.c byte_copy.c \ +byte_cr.c byte_diff.c byte_rchr.c byte_zero.c str.h str_chr.c \ +str_cpy.c str_diff.c str_diffn.c str_len.c str_rchr.c str_start.c \ +getopt.3 sgetopt.3 subgetopt.3 sgetopt.h sgetopt.c subgetopt.h \ +subgetopt.c strerr.h strerr.c strerr_sys.c strerr_die.c gen_alloc.h \ +gen_allocdefs.h stralloc.3 stralloc.h stralloc_eady.c stralloc_pend.c \ +stralloc_copy.c stralloc_opyb.c stralloc_opys.c stralloc_cat.c \ +stralloc_catb.c stralloc_cats.c stralloc_arts.c alloc.3 alloc.h \ +alloc.c alloc_re.c open.h open_append.c open_read.c open_trunc.c \ +uint32.h1 uint32.h2 tryulong32.c case.3 case.h case_diffb.c \ +case_lowerb.c case_startb.c fmt.h fmt_str.c fmt_uint.c fmt_uint0.c \ +fmt_ulong.c scan.h scan_ulong.c scan_8long.c lock.h lock_ex.c \ +tryflock.c env.3 env.h envread.c slurpclose.h slurpclose.c sig.h \ +sig_catch.c sig_pipe.c trysgact.c datetime.3 datetime.h datetime.c \ +date822fmt.h date822fmt.c now.3 now.h now.c quote.h quote.c seek.h \ +seek_set.c conf-qmail auto_qmail.h qmail.h qmail.c direntry.3 \ +direntry.h1 direntry.h2 trydrent.c getln.3 getln.h getln.c getln2.3 \ +getln2.c fd.h fd_copy.3 fd_copy.c fd_move.3 fd_move.c surf.3 surf.h \ +surf.c surfpcs.3 surfpcs.h surfpcs.c slurp.h slurp.c constmap.h \ +constmap.c + shar -m `cat FILES` > shar + chmod 400 shar + +sig.a: \ +makelib sig_catch.o sig_pipe.o + ./makelib sig.a sig_catch.o sig_pipe.o + +sig_catch.o: \ +compile sig_catch.c sig_catch.c sig.h sig_catch.c hassgact.h \ +sig_catch.c + ./compile sig_catch.c + +sig_pipe.o: \ +compile sig_pipe.c sig_pipe.c sig.h sig_pipe.c + ./compile sig_pipe.c + +slurp.o: \ +compile slurp.c stralloc.h gen_alloc.h stralloc.h slurp.c slurp.h \ +slurp.c error.h slurp.c open.h slurp.c + ./compile slurp.c + +slurpclose.o: \ +compile slurpclose.c stralloc.h gen_alloc.h stralloc.h slurpclose.c \ +readwrite.h slurpclose.c slurpclose.h slurpclose.c error.h \ +slurpclose.c + ./compile slurpclose.c + +str.a: \ +makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.o \ +str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_diff.o byte_copy.o \ +byte_cr.o byte_zero.o + ./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \ + str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o \ + byte_diff.o byte_copy.o byte_cr.o byte_zero.o + +str_chr.o: \ +compile str_chr.c str.h str_chr.c + ./compile str_chr.c + +str_cpy.o: \ +compile str_cpy.c str.h str_cpy.c + ./compile str_cpy.c + +str_diff.o: \ +compile str_diff.c str.h str_diff.c + ./compile str_diff.c + +str_diffn.o: \ +compile str_diffn.c str.h str_diffn.c + ./compile str_diffn.c + +str_len.o: \ +compile str_len.c str.h str_len.c + ./compile str_len.c + +str_rchr.o: \ +compile str_rchr.c str.h str_rchr.c + ./compile str_rchr.c + +str_start.o: \ +compile str_start.c str.h str_start.c + ./compile str_start.c + +stralloc.0: \ +stralloc.3 + nroff -man stralloc.3 > stralloc.0 + +stralloc.a: \ +makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \ +stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \ +stralloc_catb.o stralloc_arts.o + ./makelib stralloc.a stralloc_eady.o stralloc_pend.o \ + stralloc_copy.o stralloc_opys.o stralloc_opyb.o \ + stralloc_cat.o stralloc_cats.o stralloc_catb.o \ + stralloc_arts.o + +stralloc_arts.o: \ +compile stralloc_arts.c byte.h stralloc_arts.c str.h stralloc_arts.c \ +stralloc.h gen_alloc.h stralloc.h stralloc_arts.c + ./compile stralloc_arts.c + +stralloc_cat.o: \ +compile stralloc_cat.c byte.h stralloc_cat.c stralloc.h gen_alloc.h \ +stralloc.h stralloc_cat.c + ./compile stralloc_cat.c + +stralloc_catb.o: \ +compile stralloc_catb.c stralloc.h gen_alloc.h stralloc.h \ +stralloc_catb.c byte.h stralloc_catb.c + ./compile stralloc_catb.c + +stralloc_cats.o: \ +compile stralloc_cats.c byte.h stralloc_cats.c str.h stralloc_cats.c \ +stralloc.h gen_alloc.h stralloc.h stralloc_cats.c + ./compile stralloc_cats.c + +stralloc_copy.o: \ +compile stralloc_copy.c byte.h stralloc_copy.c stralloc.h gen_alloc.h \ +stralloc.h stralloc_copy.c + ./compile stralloc_copy.c + +stralloc_eady.o: \ +compile stralloc_eady.c alloc.h stralloc_eady.c stralloc.h \ +gen_alloc.h stralloc.h stralloc_eady.c gen_allocdefs.h \ +gen_allocdefs.h gen_allocdefs.h stralloc_eady.c + ./compile stralloc_eady.c + +stralloc_opyb.o: \ +compile stralloc_opyb.c stralloc.h gen_alloc.h stralloc.h \ +stralloc_opyb.c byte.h stralloc_opyb.c + ./compile stralloc_opyb.c + +stralloc_opys.o: \ +compile stralloc_opys.c byte.h stralloc_opys.c str.h stralloc_opys.c \ +stralloc.h gen_alloc.h stralloc.h stralloc_opys.c + ./compile stralloc_opys.c + +stralloc_pend.o: \ +compile stralloc_pend.c alloc.h stralloc_pend.c stralloc.h \ +gen_alloc.h stralloc.h stralloc_pend.c gen_allocdefs.h \ +gen_allocdefs.h gen_allocdefs.h stralloc_pend.c + ./compile stralloc_pend.c + +strerr.a: \ +makelib strerr.o strerr_sys.o strerr_die.o + ./makelib strerr.a strerr.o strerr_sys.o strerr_die.o + +strerr.o: \ +compile strerr.c stralloc.h gen_alloc.h stralloc.h strerr.c strerr.h \ +strerr.c + ./compile strerr.c + +strerr_die.o: \ +compile strerr_die.c substdio.h strerr_die.c subfd.h substdio.h \ +substdio.h subfd.h strerr_die.c exit.h strerr_die.c strerr.h \ +strerr_die.c + ./compile strerr_die.c + +strerr_sys.o: \ +compile strerr_sys.c error.h strerr_sys.c strerr.h strerr_sys.c + ./compile strerr_sys.c + +subfd.0: \ +subfd.3 + nroff -man subfd.3 > subfd.0 + +subfderr.o: \ +compile subfderr.c readwrite.h subfderr.c substdio.h subfderr.c \ +subfd.h substdio.h substdio.h subfd.h subfderr.c + ./compile subfderr.c + +subgetopt.0: \ +subgetopt.3 + nroff -man subgetopt.3 > subgetopt.0 + +subgetopt.o: \ +compile subgetopt.c subgetopt.h subgetopt.h subgetopt.c + ./compile subgetopt.c + +subscribe.o: \ +compile subscribe.c stralloc.h gen_alloc.h stralloc.h subscribe.c \ +getln.h subscribe.c readwrite.h subscribe.c substdio.h subscribe.c \ +strerr.h subscribe.c open.h subscribe.c byte.h subscribe.c case.h \ +subscribe.c lock.h subscribe.c error.h subscribe.c uint32.h \ +subscribe.c subscribe.h strerr.h strerr.h subscribe.h subscribe.c + ./compile subscribe.c + +substdi.o: \ +compile substdi.c substdio.h substdi.c byte.h substdi.c error.h \ +substdi.c + ./compile substdi.c + +substdio.0: \ +substdio.3 + nroff -man substdio.3 > substdio.0 + +substdio.a: \ +makelib substdio.o substdi.o substdo.o subfderr.o substdio_copy.o + ./makelib substdio.a substdio.o substdi.o substdo.o \ + subfderr.o substdio_copy.o + +substdio.o: \ +compile substdio.c substdio.h substdio.c + ./compile substdio.c + +substdio_copy.0: \ +substdio_copy.3 + nroff -man substdio_copy.3 > substdio_copy.0 + +substdio_copy.o: \ +compile substdio_copy.c substdio.h substdio_copy.c + ./compile substdio_copy.c + +substdio_in.0: \ +substdio_in.3 + nroff -man substdio_in.3 > substdio_in.0 + +substdio_out.0: \ +substdio_out.3 + nroff -man substdio_out.3 > substdio_out.0 + +substdo.o: \ +compile substdo.c substdio.h substdo.c str.h substdo.c byte.h \ +substdo.c error.h substdo.c + ./compile substdo.c + +surf.0: \ +surf.3 + nroff -man surf.3 > surf.0 + +surf.a: \ +makelib surf.o surfpcs.o + ./makelib surf.a surf.o surfpcs.o + +surf.o: \ +compile surf.c surf.h surf.c uint32.h surf.c + ./compile surf.c + +surfpcs.0: \ +surfpcs.3 + nroff -man surfpcs.3 > surfpcs.0 + +surfpcs.o: \ +compile surfpcs.c surf.h surfpcs.c surfpcs.h uint32.h surfpcs.h \ +surfpcs.c + ./compile surfpcs.c + +systype: \ +find-systype trycpp.c + ./find-systype > systype + +uint32.h: \ +tryulong32.c compile load uint32.h1 uint32.h2 + ( ( ./compile tryulong32.c && ./load tryulong32 && \ + ./tryulong32 ) >/dev/null 2>&1 \ + && cat uint32.h2 || cat uint32.h1 ) > uint32.h + rm -f tryulong32.o tryulong32 + +wait.0: \ +wait.3 + nroff -man wait.3 > wait.0 + +wait.a: \ +makelib wait_pid.o + ./makelib wait.a wait_pid.o + +wait_pid.o: \ +compile wait_pid.c wait_pid.c wait_pid.c error.h wait_pid.c + ./compile wait_pid.c diff --git a/README b/README new file mode 100644 index 0000000..f1a5806 --- /dev/null +++ b/README @@ -0,0 +1,31 @@ +ezmlm 0.53, alpha. +19970629 +Copyright 1997 +D. J. Bernstein, djb@pobox.com + +ezmlm is an easy-to-use, high-speed mailing list manager for qmail. See +BLURB for a more detailed advertisement. + +INSTALL says how to set up and test ezmlm. + +See http://pobox.com/~djb/ezmlm.html for the latest information about +ezmlm. + +The rest of this file is a list of systypes where various versions of +ezmlm have been reported to work. + +0.52: aix-4-1-:-:-:00910033a000-:- (tnx KJJ) +0.52: freebsd-2.1.6-release-:i386-:-:-:- (tnx TM) +0.52: freebsd-2.2-stable-:i386-:-:pentium-:- (tnx fedi=???) +0.52: linux-2.0.18-:i386-:-:ppro-:- (tnx MAN) +0.52: linux-2.0.28-osfmach3-:-:-:ppc-:- (tnx CWG) +0.52: linux-2.0.29-:i386-:-:i486-:- (tnx FPL) +0.52: linux-2.0.29-:i386-:-:pentium-:- (tnx AG) +0.52: linux-2.0.30-:i386-:-:pentium-:- (tnx CH) +0.52: linux-2.0.30-:i386-:-:pentium-:- (tnx LMB) +0.52: linux-2.1.32-:i386-:-:pentium-:- (tnx JF) +0.52: netbsd-1.2c-:i386-:-:intel.pentium.(p54c).(586-class)-:- (tnx GW) +0.52: news-os-6.1.2-#2-:news5000-:-:news5000-:- (tnx yamada=???) +0.52: openbsd-2.0-generic#0-:openbsd.m68k-:-:mac68k-:- (tnx GS) +0.52: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4d-:sun4d- (tnx KT) +0.52: sunos-5.5.1-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx CWG) diff --git a/SYSDEPS b/SYSDEPS new file mode 100644 index 0000000..c358b69 --- /dev/null +++ b/SYSDEPS @@ -0,0 +1,7 @@ +VERSION +systype +direntry.h +fork.h +hasflock.h +hassgact.h +uint32.h diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..d26ef09 --- /dev/null +++ b/THANKS @@ -0,0 +1,14 @@ +LMB = Lars Marowsky-Bree +EC = Evan Champion +JF = Janos Farkas +PGF = Paul Fox +CWG = Chris Garrigues +AG = Andi Gutmans +CH = Christian Hudon +KJJ = Kevin J. Johnson +FPL = Frederik P. Lindberg +TM = Toshinori Maeno +MAN = Mark Nowlin +GS = Glen Stewart +KT = Karsten Thygesen +GW = Geoff Wing diff --git a/TODO b/TODO new file mode 100644 index 0000000..1afaa05 --- /dev/null +++ b/TODO @@ -0,0 +1,7 @@ +think about how to disable ezmlm-return, ezmlm-warn +test generally +test ezmlm-warn deleting ancient files in bounce/ +test Delivered-To handling +test cookie expiration for ezmlm-return +test ezmlm-warn only handling susbcribers +test ezmlm-return only handling susbcribers diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..6049539 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +ezmlm 0.53 diff --git a/alloc.3 b/alloc.3 new file mode 100644 index 0000000..58b4432 --- /dev/null +++ b/alloc.3 @@ -0,0 +1,62 @@ +.TH alloc 3 +.SH NAME +alloc \- allocate memory +.SH SYNTAX +.B #include + +char *\fBalloc\fP(\fInew\fR); + +void \fBalloc_free\fP(\fIx\fR); + +void \fBalloc_re\fP(&\fIx\fR,\fIold\fR,\fInew\fR); + +char *\fIx\fR; +.br +unsigned int \fIold\fR; +.br +unsigned int \fInew\fR; +.SH DESCRIPTION +.B alloc +allocates enough space from the heap for +.I new +bytes of data, +adequately aligned for any data type. +.I new +may be 0. +.B alloc +returns a pointer to the space. +If space is not available, +.B alloc +returns 0, +setting +.B errno +appropriately. + +.B alloc_free +returns space to the heap. + +.B alloc_re +expands the space allocated to +.I x +from +.I old +bytes to +.I new +bytes. +It allocates new space, +copies +.I old +bytes from the old space to the new space, +returns the old space to the heap, +and changes +.I x +to point to the new space. +It then returns 1. +If space is not available, +.B alloc_re +returns 0, +leaving the old space alone. +.SH "SEE ALSO" +sbrk(2), +malloc(3), +error(3) diff --git a/alloc.c b/alloc.c new file mode 100644 index 0000000..c661453 --- /dev/null +++ b/alloc.c @@ -0,0 +1,32 @@ +#include "alloc.h" +#include "error.h" +extern char *malloc(); +extern void free(); + +#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */ +#define SPACE 4096 /* must be multiple of ALIGNMENT */ + +typedef union { char irrelevant[ALIGNMENT]; double d; } aligned; +static aligned realspace[SPACE / ALIGNMENT]; +#define space ((char *) realspace) +static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */ + +/*@null@*//*@out@*/char *alloc(n) +unsigned int n; +{ + char *x; + n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */ + if (n <= avail) { avail -= n; return space + avail; } + x = malloc(n); + if (!x) errno = error_nomem; + return x; +} + +void alloc_free(x) +char *x; +{ + if (x >= space) + if (x < space + SPACE) + return; /* XXX: assuming that pointers are flat */ + free(x); +} diff --git a/alloc.h b/alloc.h new file mode 100644 index 0000000..1b1d893 --- /dev/null +++ b/alloc.h @@ -0,0 +1,8 @@ +#ifndef ALLOC_H +#define ALLOC_H + +extern /*@null@*//*@out@*/char *alloc(); +extern void alloc_free(); +extern int alloc_re(); + +#endif diff --git a/alloc=0 b/alloc=0 new file mode 100644 index 0000000..5974100 --- /dev/null +++ b/alloc=0 @@ -0,0 +1 @@ +alloc.3 diff --git a/alloc=l b/alloc=l new file mode 100644 index 0000000..6dc62ab --- /dev/null +++ b/alloc=l @@ -0,0 +1,2 @@ +alloc.o +alloc_re.o diff --git a/alloc_re.c b/alloc_re.c new file mode 100644 index 0000000..feb8b49 --- /dev/null +++ b/alloc_re.c @@ -0,0 +1,17 @@ +#include "alloc.h" +#include "byte.h" + +int alloc_re(x,m,n) +char **x; +unsigned int m; +unsigned int n; +{ + char *y; + + y = alloc(n); + if (!y) return 0; + byte_copy(y,m,*x); + alloc_free(*x); + *x = y; + return 1; +} diff --git a/auto-str.c b/auto-str.c new file mode 100644 index 0000000..acc3d60 --- /dev/null +++ b/auto-str.c @@ -0,0 +1,44 @@ +#include "substdio.h" +#include "readwrite.h" +#include "exit.h" + +char buf1[256]; +substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); + +void puts(s) +char *s; +{ + if (substdio_puts(&ss1,s) == -1) _exit(111); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *name; + char *value; + unsigned char ch; + char octal[4]; + + name = argv[1]; + if (!name) _exit(100); + value = argv[2]; + if (!value) _exit(100); + + puts("char "); + puts(name); + puts("[] = \"\\\n"); + + while (ch = *value++) { + puts("\\"); + octal[3] = 0; + octal[2] = '0' + (ch & 7); ch >>= 3; + octal[1] = '0' + (ch & 7); ch >>= 3; + octal[0] = '0' + (ch & 7); + puts(octal); + } + + puts("\\\n\";\n"); + if (substdio_flush(&ss1) == -1) _exit(111); + _exit(0); +} diff --git a/auto-str=x b/auto-str=x new file mode 100644 index 0000000..f3e9229 --- /dev/null +++ b/auto-str=x @@ -0,0 +1,3 @@ +substdio.a +error.a +str.a diff --git a/auto_bin.c.do b/auto_bin.c.do new file mode 100644 index 0000000..8b51408 --- /dev/null +++ b/auto_bin.c.do @@ -0,0 +1,3 @@ +dependon auto-str conf-bin +formake './auto-str auto_bin `head -1 conf-bin` > auto_bin.c' +./auto-str auto_bin `head -1 conf-bin` diff --git a/auto_bin.h b/auto_bin.h new file mode 100644 index 0000000..8c30166 --- /dev/null +++ b/auto_bin.h @@ -0,0 +1,6 @@ +#ifndef AUTO_BIN_H +#define AUTO_BIN_H + +extern char auto_bin[]; + +#endif diff --git a/auto_qmail.c.do b/auto_qmail.c.do new file mode 100644 index 0000000..c072bf3 --- /dev/null +++ b/auto_qmail.c.do @@ -0,0 +1,3 @@ +dependon auto-str conf-qmail +formake './auto-str auto_qmail `head -1 conf-qmail` > auto_qmail.c' +./auto-str auto_qmail `head -1 conf-qmail` diff --git a/auto_qmail.h b/auto_qmail.h new file mode 100644 index 0000000..0c56001 --- /dev/null +++ b/auto_qmail.h @@ -0,0 +1,6 @@ +#ifndef AUTO_QMAIL_H +#define AUTO_QMAIL_H + +extern char auto_qmail[]; + +#endif diff --git a/byte.h b/byte.h new file mode 100644 index 0000000..de06c69 --- /dev/null +++ b/byte.h @@ -0,0 +1,13 @@ +#ifndef BYTE_H +#define BYTE_H + +extern unsigned int byte_chr(); +extern unsigned int byte_rchr(); +extern void byte_copy(); +extern void byte_copyr(); +extern int byte_diff(); +extern void byte_zero(); + +#define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) + +#endif diff --git a/byte_chr.c b/byte_chr.c new file mode 100644 index 0000000..f81dde8 --- /dev/null +++ b/byte_chr.c @@ -0,0 +1,20 @@ +#include "byte.h" + +unsigned int byte_chr(s,n,c) +char *s; +register unsigned int n; +int c; +{ + register char ch; + register char *t; + + ch = c; + t = s; + for (;;) { + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + } + return t - s; +} diff --git a/byte_copy.c b/byte_copy.c new file mode 100644 index 0000000..eaad11b --- /dev/null +++ b/byte_copy.c @@ -0,0 +1,14 @@ +#include "byte.h" + +void byte_copy(to,n,from) +register char *to; +register unsigned int n; +register char *from; +{ + for (;;) { + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + } +} diff --git a/byte_cr.c b/byte_cr.c new file mode 100644 index 0000000..3e7a1d5 --- /dev/null +++ b/byte_cr.c @@ -0,0 +1,16 @@ +#include "byte.h" + +void byte_copyr(to,n,from) +register char *to; +register unsigned int n; +register char *from; +{ + to += n; + from += n; + for (;;) { + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + } +} diff --git a/byte_diff.c b/byte_diff.c new file mode 100644 index 0000000..cdbd760 --- /dev/null +++ b/byte_diff.c @@ -0,0 +1,16 @@ +#include "byte.h" + +int byte_diff(s,n,t) +register char *s; +register unsigned int n; +register char *t; +{ + for (;;) { + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + } + return ((int)(unsigned int)(unsigned char) *s) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/byte_rchr.c b/byte_rchr.c new file mode 100644 index 0000000..476bc22 --- /dev/null +++ b/byte_rchr.c @@ -0,0 +1,23 @@ +#include "byte.h" + +unsigned int byte_rchr(s,n,c) +char *s; +register unsigned int n; +int c; +{ + register char ch; + register char *t; + register char *u; + + ch = c; + t = s; + u = 0; + for (;;) { + if (!n) break; if (*t == ch) u = t; ++t; --n; + if (!n) break; if (*t == ch) u = t; ++t; --n; + if (!n) break; if (*t == ch) u = t; ++t; --n; + if (!n) break; if (*t == ch) u = t; ++t; --n; + } + if (!u) u = t; + return u - s; +} diff --git a/byte_zero.c b/byte_zero.c new file mode 100644 index 0000000..92009ba --- /dev/null +++ b/byte_zero.c @@ -0,0 +1,13 @@ +#include "byte.h" + +void byte_zero(s,n) +char *s; +register unsigned int n; +{ + for (;;) { + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + } +} diff --git a/case.3 b/case.3 new file mode 100644 index 0000000..58bd724 --- /dev/null +++ b/case.3 @@ -0,0 +1,100 @@ +.TH case 3 +.SH NAME +case \- convert ASCII uppercase bytes to lowercase +.SH SYNTAX +.B #include + +void \fBcase_lowers\fP(\fIs\fR); +.br +void \fBcase_lowerb\fP(\fIs\fR,\fIlen\fR); + +int \fBcase_diffs\fP(\fIs\fR,\fIt\fR); +.br +int \fBcase_equals\fP(\fIs\fR,\fIt\fR); +.br +int \fBcase_starts\fP(\fIs\fR,\fIt\fR); + +int \fBcase_diffb\fP(\fIs\fR,\fIlen\fR,\fIt\fR); +.br +int \fBcase_startb\fP(\fIs\fR,\fIlen\fR,\fIt\fR); + +char *\fIs\fR; +.br +char *\fIt\fR; +.br +unsigned int \fIlen\fR; +.SH DESCRIPTION +.B case_lowers +converts each uppercase byte in the string +.I s +to lowercase. +.I s +must be 0-terminated. + +.B case_lowerb +converts each uppercase byte in the buffer +.IR s , +of length +.IR len , +to lowercase. + +.B case_diffs +lexicographically compares lowercase versions of the strings +.I s +and +.IR t . +It returns something positive, negative, or zero +when the first is larger than, smaller than, or equal to the second. +.I s +and +.I t +must be 0-terminated. + +.B case_equals +means +.BR !case_diffs . + +.B case_starts +returns 1 if a lowercase version of +.I s +starts with a lowercase version of +.IR t . +.I s +and +.I t +must be 0-terminated. + +.B case_diffb +lexicographically compares lowercase versions of the buffers +.I s +and +.IR t , +each of length +.IR len . +It returns something positive, negative, or zero +when the first is larger than, smaller than, or equal to the second. + +.B case_startb +returns 1 if a lowercase version of the buffer +.IR s , +of length +.IR len , +starts with a lowercase version of the string +.IR t . +.I t +must be 0-terminated. + +The +.B case +routines +are ASCII-specific. +They are suitable for programs that handle +case-independent networking protocols. + +All comparisons are performed on unsigned bytes. +.SH "SEE ALSO" +byte_diff(3), +byte_equal(3), +str_diff(3), +str_equal(3), +str_start(3) diff --git a/case.h b/case.h new file mode 100644 index 0000000..35a2434 --- /dev/null +++ b/case.h @@ -0,0 +1,13 @@ +#ifndef CASE_H +#define CASE_H + +extern void case_lowers(); +extern void case_lowerb(); +extern int case_diffs(); +extern int case_diffb(); +extern int case_starts(); +extern int case_startb(); + +#define case_equals(s,t) (!case_diffs((s),(t))) + +#endif diff --git a/case=0 b/case=0 new file mode 100644 index 0000000..4750e7f --- /dev/null +++ b/case=0 @@ -0,0 +1 @@ +case.3 diff --git a/case=l b/case=l new file mode 100644 index 0000000..9e09750 --- /dev/null +++ b/case=l @@ -0,0 +1,3 @@ +case_diffb.o +case_lowerb.o +case_startb.o diff --git a/case_diffb.c b/case_diffb.c new file mode 100644 index 0000000..9064b8a --- /dev/null +++ b/case_diffb.c @@ -0,0 +1,21 @@ +#include "case.h" + +int case_diffb(s,len,t) +register char *s; +unsigned int len; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + while (len > 0) { + --len; + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (x != y) + return ((int)(unsigned int) x) - ((int)(unsigned int) y); + } + return 0; +} diff --git a/case_lowerb.c b/case_lowerb.c new file mode 100644 index 0000000..4034c14 --- /dev/null +++ b/case_lowerb.c @@ -0,0 +1,14 @@ +#include "case.h" + +void case_lowerb(s,len) +char *s; +unsigned int len; +{ + unsigned char x; + while (len > 0) { + --len; + x = *s - 'A'; + if (x <= 'Z' - 'A') *s = x + 'a'; + ++s; + } +} diff --git a/case_startb.c b/case_startb.c new file mode 100644 index 0000000..ee88efe --- /dev/null +++ b/case_startb.c @@ -0,0 +1,21 @@ +#include "case.h" + +int case_startb(s,len,t) +register char *s; +unsigned int len; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + for (;;) { + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (!y) return 1; + if (!len) return 0; + --len; + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + if (x != y) return 0; + } +} diff --git a/conf-bin b/conf-bin new file mode 100644 index 0000000..813dc94 --- /dev/null +++ b/conf-bin @@ -0,0 +1,3 @@ +/usr/local/bin/ezmlm + +Programs will be installed in this directory. diff --git a/conf-cc b/conf-cc new file mode 100644 index 0000000..e58fb9b --- /dev/null +++ b/conf-cc @@ -0,0 +1,3 @@ +cc -O2 + +This will be used to compile .c files. diff --git a/conf-ld b/conf-ld new file mode 100644 index 0000000..a9e796a --- /dev/null +++ b/conf-ld @@ -0,0 +1,3 @@ +cc -s + +This will be used to link .o files into an executable. diff --git a/conf-man b/conf-man new file mode 100644 index 0000000..b4e70a4 --- /dev/null +++ b/conf-man @@ -0,0 +1,5 @@ +/usr/local/man + +Man pages will be installed in subdirectories of this directory. An +unformatted man page foo.1 will go into .../man1/foo.1; a formatted man +page foo.0 will go into .../cat1/foo.0. diff --git a/conf-qmail b/conf-qmail new file mode 100644 index 0000000..6acc5a5 --- /dev/null +++ b/conf-qmail @@ -0,0 +1,3 @@ +/var/qmail + +This is the qmail home directory. diff --git a/constmap.c b/constmap.c new file mode 100644 index 0000000..722e3b8 --- /dev/null +++ b/constmap.c @@ -0,0 +1,114 @@ +#include "constmap.h" +#include "alloc.h" +#include "case.h" + +static constmap_hash hash(s,len) +char *s; +int len; +{ + unsigned char ch; + constmap_hash h; + h = 5381; + while (len > 0) { + ch = *s++ - 'A'; + if (ch <= 'Z' - 'A') ch += 'a' - 'A'; + h = ((h << 5) + h) ^ ch; + --len; + } + return h; +} + +char *constmap(cm,s,len) +struct constmap *cm; +char *s; +int len; +{ + constmap_hash h; + int pos; + h = hash(s,len); + pos = cm->first[h & cm->mask]; + while (pos != -1) { + if (h == cm->hash[pos]) + if (len == cm->inputlen[pos]) + if (!case_diffb(cm->input[pos],len,s)) + return cm->input[pos] + cm->inputlen[pos] + 1; + pos = cm->next[pos]; + } + return 0; +} + +int constmap_init(cm,s,len,flagcolon) +struct constmap *cm; +char *s; +int len; +int flagcolon; +{ + int i; + int j; + int k; + int pos; + constmap_hash h; + + cm->num = 0; + for (j = 0;j < len;++j) if (!s[j]) ++cm->num; + + h = 64; + while (h && (h < cm->num)) h += h; + cm->mask = h - 1; + + cm->first = (int *) alloc(sizeof(int) * h); + if (cm->first) { + cm->input = (char **) alloc(sizeof(char *) * cm->num); + if (cm->input) { + cm->inputlen = (int *) alloc(sizeof(int) * cm->num); + if (cm->inputlen) { + cm->hash = (constmap_hash *) alloc(sizeof(constmap_hash) * cm->num); + if (cm->hash) { + cm->next = (int *) alloc(sizeof(int) * cm->num); + if (cm->next) { + for (h = 0;h <= cm->mask;++h) + cm->first[h] = -1; + pos = 0; + i = 0; + for (j = 0;j < len;++j) + if (!s[j]) { + k = j - i; + if (flagcolon) { + for (k = i;k < j;++k) + if (s[k] == ':') + break; + if (k >= j) { i = j + 1; continue; } + k -= i; + } + cm->input[pos] = s + i; + cm->inputlen[pos] = k; + h = hash(s + i,k); + cm->hash[pos] = h; + h &= cm->mask; + cm->next[pos] = cm->first[h]; + cm->first[h] = pos; + ++pos; + i = j + 1; + } + return 1; + } + alloc_free(cm->hash); + } + alloc_free(cm->inputlen); + } + alloc_free(cm->input); + } + alloc_free(cm->first); + } + return 0; +} + +void constmap_free(cm) +struct constmap *cm; +{ + alloc_free(cm->next); + alloc_free(cm->hash); + alloc_free(cm->inputlen); + alloc_free(cm->input); + alloc_free(cm->first); +} diff --git a/constmap.h b/constmap.h new file mode 100644 index 0000000..3f29179 --- /dev/null +++ b/constmap.h @@ -0,0 +1,20 @@ +#ifndef CONSTMAP_H +#define CONSTMAP_H + +typedef unsigned long constmap_hash; + +struct constmap { + int num; + constmap_hash mask; + constmap_hash *hash; + int *first; + int *next; + char **input; + int *inputlen; +} ; + +extern int constmap_init(); +extern void constmap_free(); +extern char *constmap(); + +#endif diff --git a/cookie.c b/cookie.c new file mode 100644 index 0000000..59089c1 --- /dev/null +++ b/cookie.c @@ -0,0 +1,47 @@ +#include "cookie.h" +#include "str.h" +#include "uint32.h" +#include "surfpcs.h" + +void cookie(hash,key,keylen,date,addr,action) +char *hash; +char *key; +unsigned int keylen; +char *date; +char *addr; +char *action; +{ + surfpcs s; + uint32 seed[32]; + unsigned char out[32]; + int i; + int j; + +/* +step 1: create seed from key. note that this doesn't have to be +cryptographic; it simply has to avoid destroying the user's entropy. +if speed turns out to be a problem, switch to a CRC. +*/ + for (i = 0;i < 32;++i) seed[i] = 0; + for (j = 0;j < 4;++j) { + surfpcs_init(&s,seed); + surfpcs_add(&s,key,keylen); + surfpcs_out(&s,out); + for (i = 0;i < 32;++i) seed[i] = (seed[i] << 8) + out[i]; + } + +/* +step 2: apply SURF. +*/ + surfpcs_init(&s,seed); + surfpcs_add(&s,date,str_len(date) + 1); + surfpcs_add(&s,addr,str_len(addr) + 1); + surfpcs_add(&s,action,1); + surfpcs_out(&s,out); + +/* +step 3: extract a readable cookie from the SURF output. +*/ + for (i = 0;i < 20;++i) + hash[i] = 'a' + (out[i] & 15); +} diff --git a/cookie.h b/cookie.h new file mode 100644 index 0000000..041cb6a --- /dev/null +++ b/cookie.h @@ -0,0 +1,8 @@ +#ifndef COOKIE_H +#define COOKIE_H + +#define COOKIE 20 + +extern void cookie(); + +#endif diff --git a/date822fmt.c b/date822fmt.c new file mode 100644 index 0000000..7674bd1 --- /dev/null +++ b/date822fmt.c @@ -0,0 +1,29 @@ +#include "datetime.h" +#include "fmt.h" +#include "date822fmt.h" + +static char *montab[12] = { +"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +unsigned int date822fmt(s,dt) +char *s; +struct datetime *dt; +{ + unsigned int i; + unsigned int len; + len = 0; + i = fmt_uint(s,dt->mday); len += i; if (s) s += i; + i = fmt_str(s," "); len += i; if (s) s += i; + i = fmt_str(s,montab[dt->mon]); len += i; if (s) s += i; + i = fmt_str(s," "); len += i; if (s) s += i; + i = fmt_uint(s,dt->year + 1900); len += i; if (s) s += i; + i = fmt_str(s," "); len += i; if (s) s += i; + i = fmt_uint0(s,dt->hour,2); len += i; if (s) s += i; + i = fmt_str(s,":"); len += i; if (s) s += i; + i = fmt_uint0(s,dt->min,2); len += i; if (s) s += i; + i = fmt_str(s,":"); len += i; if (s) s += i; + i = fmt_uint0(s,dt->sec,2); len += i; if (s) s += i; + i = fmt_str(s," -0000\n"); len += i; if (s) s += i; + return len; +} diff --git a/date822fmt.h b/date822fmt.h new file mode 100644 index 0000000..1848e5a --- /dev/null +++ b/date822fmt.h @@ -0,0 +1,7 @@ +#ifndef DATE822FMT_H +#define DATE822FMT_H + +extern unsigned int date822fmt(); +#define DATE822FMT 60 + +#endif diff --git a/datetime.3 b/datetime.3 new file mode 100644 index 0000000..33a623f --- /dev/null +++ b/datetime.3 @@ -0,0 +1,73 @@ +.TH datetime 3 +.SH NAME +datetime \- convert between TAI labels and seconds +.SH SYNTAX +.B #include + +void \fBdatetime_tai\fP(&\fIdt\fR,\fIt\fR); + +datetime_sec \fBdatetime_untai\fP(&\fIdt\fR); + +struct datetime \fIdt\fR; +.br +datetime_sec \fIt\fR; +.SH DESCRIPTION +International Atomic Time, TAI, +is the fundamental unit for time measurements. +TAI has one label for every second of real time, +without complications such as leap seconds. + +A +struct datetime +variable, +such as +.IR dt , +stores a TAI label. +.I dt\fB.year +is the year number minus 1900; +.I dt\fB.mon +is the month number, from 0 (January) through 11 (December); +.I dt\fB.mday +is the day of the month, from 1 through 31; +.I dt\fB.hour +is the hour, from 0 through 23; +.I dt\fB.min +is the minute, from 0 through 59; +.I dt\fB.sec +is the second, from 0 through 59; +.I dt\fB.wday +is the day of the week, from 0 (Sunday) through 6 (Saturday); +.I dt\fB.yday +is the day of the year, from 0 through 365. + +The +.B datetime +library supports more convenient TAI manipulation with +the datetime_sec type. +A datetime_sec value, such as +.IR t , +is an integer referring to the +.IR t th +second after the beginning of 1970 TAI. +The first second of 1970 TAI was 0; +the next second was 1; +the last second of 1969 TAI was -1. +The difference between two datetime_sec values is a number +of real-time seconds. + +.B datetime_tai +converts a datetime_sec to a TAI label. + +.B datetime_untai +reads a TAI label +(specifically +.IR dt\fB.year , +.IR dt\fB.mon , +.IR dt\fB.mday , +.IR dt\fB.hour , +.IR dt\fB.min , +and +.IR dt\fB.sec ) +and returns a datetime_sec. +.SH "SEE ALSO" +now(3) diff --git a/datetime.c b/datetime.c new file mode 100644 index 0000000..7b8a803 --- /dev/null +++ b/datetime.c @@ -0,0 +1,55 @@ +/* 19950925 */ +#include "datetime.h" + +void datetime_tai(dt,t) +struct datetime *dt; +datetime_sec t; +{ + int day; + int tod; + int year; + int yday; + int wday; + int mon; + + tod = t % 86400; + day = t / 86400; + if (tod < 0) { tod += 86400; --day; } + + dt->hour = tod / 3600; + tod %= 3600; + dt->min = tod / 60; + dt->sec = tod % 60; + + wday = (day + 4) % 7; if (wday < 0) wday += 7; + dt->wday = wday; + + day -= 11017; + /* day 0 is march 1, 2000 */ + year = 5 + day / 146097; + day = day % 146097; if (day < 0) { day += 146097; --year; } + /* from now on, day is nonnegative */ + year *= 4; + if (day == 146096) { year += 3; day = 36524; } + else { year += day / 36524; day %= 36524; } + year *= 25; + year += day / 1461; + day %= 1461; + year *= 4; + yday = (day < 306); + if (day == 1460) { year += 3; day = 365; } + else { year += day / 365; day %= 365; } + yday += day; + + day *= 10; + mon = (day + 5) / 306; + day = day + 5 - 306 * mon; + day /= 10; + if (mon >= 10) { yday -= 306; ++year; mon -= 10; } + else { yday += 59; mon += 2; } + + dt->yday = yday; + dt->year = year - 1900; + dt->mon = mon; + dt->mday = day + 1; +} diff --git a/datetime.h b/datetime.h new file mode 100644 index 0000000..cde2a9b --- /dev/null +++ b/datetime.h @@ -0,0 +1,20 @@ +#ifndef DATETIME_H +#define DATETIME_H + +struct datetime { + int hour; + int min; + int sec; + int wday; + int mday; + int yday; + int mon; + int year; +} ; + +typedef long datetime_sec; + +extern void datetime_tai(); +extern datetime_sec datetime_untai(); + +#endif diff --git a/datetime=0 b/datetime=0 new file mode 100644 index 0000000..8a4bea1 --- /dev/null +++ b/datetime=0 @@ -0,0 +1 @@ +datetime.3 diff --git a/default.0.do b/default.0.do new file mode 100644 index 0000000..e40b50c --- /dev/null +++ b/default.0.do @@ -0,0 +1,9 @@ +if test -r "$2=0" +then + dependon "$2=0" + dependon `cat "$2=0"` + nroff -man `cat "$2=0"` + formake nroff -man `cat "$2=0"` '>' $1 +else + nosuchtarget +fi diff --git a/default.a.do b/default.a.do new file mode 100644 index 0000000..b61fc5c --- /dev/null +++ b/default.a.do @@ -0,0 +1,10 @@ +if test -r "$2=l" +then + dependon "$2=l" + dependon makelib `cat "$2=l"` + directtarget + formake ./makelib $1 `cat "$2=l"` + ./makelib $1 `cat "$2=l"` +else + nosuchtarget +fi diff --git a/default.do b/default.do new file mode 100644 index 0000000..792917f --- /dev/null +++ b/default.do @@ -0,0 +1,76 @@ +if test -r $1=x +then + dependon $1=x + libs=`grep '\.lib *$' "$1=x"` + libscat='' + for i in $libs + do + libscat="$libscat "'`'"cat $i"'`' + done + objs=`grep -v '\.lib *$' "$1=x"` + dependon load $1.o $objs $libs + directtarget + formake ./load $1 $objs "$libscat" + eval ./load $1 $objs $libscat + exit 0 +fi + +if test -r $1=s +then + dependon $1=s warn-auto.sh $1.sh + formake cat warn-auto.sh $1.sh '>' $1 + formake chmod 755 $1 + cat warn-auto.sh $1.sh + chmod 755 $3 + exit 0 +fi + +case "$1" in + shar) + dependon FILES `cat FILES` + formake 'shar -m `cat FILES` > shar' + formake 'chmod 400 shar' + shar -m `cat FILES` + chmod 400 $3 + ;; + compile|load|makelib) + dependon make-$1 warn-auto.sh systype + formake "( cat warn-auto.sh; ./make-$1 "'"`cat systype`"'" ) > $1" + formake "chmod 755 $1" + cat warn-auto.sh + ./make-$1 "`cat systype`" + chmod 755 $3 + ;; + make-compile|make-load|make-makelib) + dependon $1.sh auto-ccld.sh + formake "cat auto-ccld.sh $1.sh > $1" + formake "chmod 755 $1" + cat auto-ccld.sh $1.sh + chmod 755 $3 + ;; + systype) + dependon find-systype trycpp.c + formake './find-systype > systype' + ./find-systype + ;; + find-systype) + dependon find-systype.sh auto-ccld.sh + formake 'cat auto-ccld.sh find-systype.sh > find-systype' + formake 'chmod 755 find-systype' + cat auto-ccld.sh find-systype.sh + chmod 755 $3 + ;; + auto-ccld.sh) + dependon conf-cc conf-ld warn-auto.sh + formake '( cat warn-auto.sh; \' + formake 'echo CC=\'\''`head -1 conf-cc`\'\''; \' + formake 'echo LD=\'\''`head -1 conf-ld`\'\'' \' + formake ') > auto-ccld.sh' + cat warn-auto.sh + echo CC=\'`head -1 conf-cc`\' + echo LD=\'`head -1 conf-ld`\' + ;; + *) + nosuchtarget + ;; +esac diff --git a/default.o.do b/default.o.do new file mode 100644 index 0000000..5d5ee1e --- /dev/null +++ b/default.o.do @@ -0,0 +1,15 @@ +if test -r $2=m +then + dependon $2=m $2.s + directtarget + as -o $1 $2.s + formake as -o $1 $2.s + exit 0 +fi +depend -$2=m + +directtarget +dependon compile +dependcc $2.c +formake ./compile $2.c +./compile $2.c diff --git a/direntry.3 b/direntry.3 new file mode 100644 index 0000000..8928fbb --- /dev/null +++ b/direntry.3 @@ -0,0 +1,36 @@ +.TH direntry 3 +.SH NAME +direntry \- read directory entries +.SH SYNTAX +.B #include + +DIR *\fBopendir\fP(\fIfn\fR); + +struct direntry *\fBreaddir\fP(\fIdir\fP); + +void \fBclosedir\fP(\fIdir\fP); + +DIR *\fIdir\fR; +.br +char *\fIfn\fR; +.SH DESCRIPTION +The point of +.B direntry.h +is to provide a uniform interface to BSD's +.B sys/dir.h +and POSIX's +.BR dirent.h . + +The +.B readdir +interface is highly unsatisfactory. +It does not distinguish between I/O errors and end-of-directory. +It uses +.BR malloc . +The return type for +.B closedir +varies: some implementations return the +.B close +return value. +.SH "SEE ALSO" +readdir(3) diff --git a/direntry.h.do b/direntry.h.do new file mode 100644 index 0000000..4470197 --- /dev/null +++ b/direntry.h.do @@ -0,0 +1,7 @@ +dependon compile trydrent.c direntry.h1 direntry.h2 +./compile trydrent.c >/dev/null 2>&1 \ +&& cat direntry.h2 || cat direntry.h1 +rm -f trydrent.o +formake '( ./compile trydrent.c >/dev/null 2>&1 \' +formake '&& cat direntry.h2 || cat direntry.h1 ) > direntry.h' +formake 'rm -f trydrent.o' diff --git a/direntry.h1 b/direntry.h1 new file mode 100644 index 0000000..f737676 --- /dev/null +++ b/direntry.h1 @@ -0,0 +1,8 @@ +#ifndef DIRENTRY_H +#define DIRENTRY_H + +#include +#include +#define direntry struct direct + +#endif diff --git a/direntry.h2 b/direntry.h2 new file mode 100644 index 0000000..0302ebe --- /dev/null +++ b/direntry.h2 @@ -0,0 +1,8 @@ +#ifndef DIRENTRY_H +#define DIRENTRY_H + +#include +#include +#define direntry struct dirent + +#endif diff --git a/direntry=0 b/direntry=0 new file mode 100644 index 0000000..6086256 --- /dev/null +++ b/direntry=0 @@ -0,0 +1 @@ +direntry.3 diff --git a/env.3 b/env.3 new file mode 100644 index 0000000..53a5f89 --- /dev/null +++ b/env.3 @@ -0,0 +1,31 @@ +.TH env 3 +.SH NAME +env \- manage the environment +.SH SYNTAX +.B #include + +char **\fBenviron\fP; + +char *\fBenv_get\fP(\fIname\fR); +.br +char *\fBenv_pick\fP(); + +char *\fIname\fR; +.SH DESCRIPTION +The environment, +.BR environ , +is a 0-terminated array of 0-terminated strings, +called environment variables. +Each environment variable is of the form +.IR name\fB=\fIvalue . + +.B env_get +returns the value of the first variable whose name is +.IR name , +or 0 if there is no such variable. + +.B env_pick +returns any variable in the environment, +or 0 if the environment is empty. +.SH "SEE ALSO" +environ(7) diff --git a/env.h b/env.h new file mode 100644 index 0000000..9befc79 --- /dev/null +++ b/env.h @@ -0,0 +1,17 @@ +#ifndef ENV_H +#define ENV_H + +extern int env_isinit; + +extern int env_init(); +extern int env_put(); +extern int env_put2(); +extern int env_unset(); +extern /*@null@*/char *env_get(); +extern char *env_pick(); +extern void env_clear(); +extern char *env_findeq(); + +extern char **environ; + +#endif diff --git a/env=0 b/env=0 new file mode 100644 index 0000000..567ab81 --- /dev/null +++ b/env=0 @@ -0,0 +1 @@ +env.3 diff --git a/env=l b/env=l new file mode 100644 index 0000000..21db6c5 --- /dev/null +++ b/env=l @@ -0,0 +1 @@ +envread.o diff --git a/envread.c b/envread.c new file mode 100644 index 0000000..80185de --- /dev/null +++ b/envread.c @@ -0,0 +1,30 @@ +#include "env.h" +#include "str.h" + +extern /*@null@*/char *env_get(s) +char *s; +{ + int i; + unsigned int slen; + char *envi; + + slen = str_len(s); + for (i = 0;envi = environ[i];++i) + if ((!str_diffn(s,envi,slen)) && (envi[slen] == '=')) + return envi + slen + 1; + return 0; +} + +extern char *env_pick() +{ + return environ[0]; +} + +extern char *env_findeq(s) +char *s; +{ + for (;*s;++s) + if (*s == '=') + return s; + return 0; +} diff --git a/error.3 b/error.3 new file mode 100644 index 0000000..e955b35 --- /dev/null +++ b/error.3 @@ -0,0 +1,45 @@ +.TH error 3 +.SH NAME +error \- syscall error codes +.SH SYNTAX +.B #include + +extern int \fBerrno\fP; + +extern int \fBerror_intr\fP; +.br +extern int \fBerror_nomem\fP; +.br +extern int \fBerror_noent\fP; +.br +extern int \fBerror_txtbsy\fP; +.br +extern int \fBerror_io\fP; +.br +extern int \fBerror_exist\fP; +.br +extern int \fBerror_timeout\fP; +.br +extern int \fBerror_inprogress\fP; +.br +extern int \fBerror_wouldblock\fP; +.br +extern int \fBerror_again\fP; +.br +extern int \fBerror_pipe\fP; +.br +extern int \fBerror_perm\fP; +.br +extern int \fBerror_acces\fP; +.SH DESCRIPTION +UNIX syscalls provide detailed error codes in the +.B errno +variable. +The +.B error +library provides portable names for a variety of possible +.B errno +values. +.SH "SEE ALSO" +error_str(3), +error_temp(3) diff --git a/error.c b/error.c new file mode 100644 index 0000000..d51304f --- /dev/null +++ b/error.c @@ -0,0 +1,95 @@ +#include +#include "error.h" + +/* warning: as coverage improves here, should update error_{str,temp} */ + +int error_intr = +#ifdef EINTR +EINTR; +#else +-1; +#endif + +int error_nomem = +#ifdef ENOMEM +ENOMEM; +#else +-2; +#endif + +int error_noent = +#ifdef ENOENT +ENOENT; +#else +-3; +#endif + +int error_txtbsy = +#ifdef ETXTBSY +ETXTBSY; +#else +-4; +#endif + +int error_io = +#ifdef EIO +EIO; +#else +-5; +#endif + +int error_exist = +#ifdef EEXIST +EEXIST; +#else +-6; +#endif + +int error_timeout = +#ifdef ETIMEDOUT +ETIMEDOUT; +#else +-7; +#endif + +int error_inprogress = +#ifdef EINPROGRESS +EINPROGRESS; +#else +-8; +#endif + +int error_wouldblock = +#ifdef EWOULDBLOCK +EWOULDBLOCK; +#else +-9; +#endif + +int error_again = +#ifdef EAGAIN +EAGAIN; +#else +-10; +#endif + +int error_pipe = +#ifdef EPIPE +EPIPE; +#else +-11; +#endif + +int error_perm = +#ifdef EPERM +EPERM; +#else +-12; +#endif + +int error_acces = +#ifdef EACCES +EACCES; +#else +-13; +#endif diff --git a/error.h b/error.h new file mode 100644 index 0000000..01bd3dc --- /dev/null +++ b/error.h @@ -0,0 +1,23 @@ +#ifndef ERROR_H +#define ERROR_H + +extern int errno; + +extern int error_intr; +extern int error_nomem; +extern int error_noent; +extern int error_txtbsy; +extern int error_io; +extern int error_exist; +extern int error_timeout; +extern int error_inprogress; +extern int error_wouldblock; +extern int error_again; +extern int error_pipe; +extern int error_perm; +extern int error_acces; + +extern char *error_str(); +extern int error_temp(); + +#endif diff --git a/error=0 b/error=0 new file mode 100644 index 0000000..d7bbc09 --- /dev/null +++ b/error=0 @@ -0,0 +1 @@ +error.3 diff --git a/error=l b/error=l new file mode 100644 index 0000000..2a9cb84 --- /dev/null +++ b/error=l @@ -0,0 +1,2 @@ +error.o +error_str.o diff --git a/error_str.3 b/error_str.3 new file mode 100644 index 0000000..62043c4 --- /dev/null +++ b/error_str.3 @@ -0,0 +1,19 @@ +.TH error_str 3 +.SH NAME +error_str \- names for syscall error codes +.SH SYNTAX +.B #include + +char *\fBerror_str\fP(\fIe\fR); + +int \fIe\fR; +.SH DESCRIPTION +.B error_str +returns a printable string describing syscall error code +.IR e . +Normally +.I e +is +.BR errno . +.SH "SEE ALSO" +error(3) diff --git a/error_str.c b/error_str.c new file mode 100644 index 0000000..804d1fa --- /dev/null +++ b/error_str.c @@ -0,0 +1,276 @@ +#include +#include "error.h" + +#define X(e,s) if (i == e) return s; + +char *error_str(i) +int i; +{ + X(0,"no error") + X(error_intr,"interrupted system call") + X(error_nomem,"out of memory") + X(error_noent,"file does not exist") + X(error_txtbsy,"text busy") + X(error_io,"input/output error") + X(error_exist,"file already exists") + X(error_timeout,"timed out") + X(error_inprogress,"operation in progress") + X(error_again,"temporary failure") + X(error_wouldblock,"input/output would block") + X(error_pipe,"broken pipe") + X(error_perm,"permission denied") + X(error_acces,"access denied") +#ifdef ESRCH + X(ESRCH,"no such process") +#endif +#ifdef ENXIO + X(ENXIO,"device not configured") +#endif +#ifdef E2BIG + X(E2BIG,"argument list too long") +#endif +#ifdef ENOEXEC + X(ENOEXEC,"exec format error") +#endif +#ifdef EBADF + X(EBADF,"file descriptor not open") +#endif +#ifdef ECHILD + X(ECHILD,"no child processes") +#endif +#ifdef EDEADLK + X(EDEADLK,"operation would cause deadlock") +#endif +#ifdef EFAULT + X(EFAULT,"bad address") +#endif +#ifdef ENOTBLK + X(ENOTBLK,"not a block device") +#endif +#ifdef EBUSY + X(EBUSY,"device busy") +#endif +#ifdef EXDEV + X(EXDEV,"cross-device link") +#endif +#ifdef ENODEV + X(ENODEV,"device does not support operation") +#endif +#ifdef ENOTDIR + X(ENOTDIR,"not a directory") +#endif +#ifdef EISDIR + X(EISDIR,"is a directory") +#endif +#ifdef EINVAL + X(EINVAL,"invalid argument") +#endif +#ifdef ENFILE + X(ENFILE,"system cannot open more files") +#endif +#ifdef EMFILE + X(EMFILE,"process cannot open more files") +#endif +#ifdef ENOTTY + X(ENOTTY,"not a tty") +#endif +#ifdef EFBIG + X(EFBIG,"file too big") +#endif +#ifdef ENOSPC + X(ENOSPC,"out of disk space") +#endif +#ifdef ESPIPE + X(ESPIPE,"unseekable descriptor") +#endif +#ifdef EROFS + X(EROFS,"read-only file system") +#endif +#ifdef EMLINK + X(EMLINK,"too many links") +#endif +#ifdef EDOM + X(EDOM,"input out of range") +#endif +#ifdef ERANGE + X(ERANGE,"output out of range") +#endif +#ifdef EALREADY + X(EALREADY,"operation already in progress") +#endif +#ifdef ENOTSOCK + X(ENOTSOCK,"not a socket") +#endif +#ifdef EDESTADDRREQ + X(EDESTADDRREQ,"destination address required") +#endif +#ifdef EMSGSIZE + X(EMSGSIZE,"message too long") +#endif +#ifdef EPROTOTYPE + X(EPROTOTYPE,"incorrect protocol type") +#endif +#ifdef ENOPROTOOPT + X(ENOPROTOOPT,"protocol not available") +#endif +#ifdef EPROTONOSUPPORT + X(EPROTONOSUPPORT,"protocol not supported") +#endif +#ifdef ESOCKTNOSUPPORT + X(ESOCKTNOSUPPORT,"socket type not supported") +#endif +#ifdef EOPNOTSUPP + X(EOPNOTSUPP,"operation not supported") +#endif +#ifdef EPFNOSUPPORT + X(EPFNOSUPPORT,"protocol family not supported") +#endif +#ifdef EAFNOSUPPORT + X(EAFNOSUPPORT,"address family not supported") +#endif +#ifdef EADDRINUSE + X(EADDRINUSE,"address already used") +#endif +#ifdef EADDRNOTAVAIL + X(EADDRNOTAVAIL,"address not available") +#endif +#ifdef ENETDOWN + X(ENETDOWN,"network down") +#endif +#ifdef ENETUNREACH + X(ENETUNREACH,"network unreachable") +#endif +#ifdef ENETRESET + X(ENETRESET,"network reset") +#endif +#ifdef ECONNABORTED + X(ECONNABORTED,"connection aborted") +#endif +#ifdef ECONNRESET + X(ECONNRESET,"connection reset") +#endif +#ifdef ENOBUFS + X(ENOBUFS,"out of buffer space") +#endif +#ifdef EISCONN + X(EISCONN,"already connected") +#endif +#ifdef ENOTCONN + X(ENOTCONN,"not connected") +#endif +#ifdef ESHUTDOWN + X(ESHUTDOWN,"socket shut down") +#endif +#ifdef ETOOMANYREFS + X(ETOOMANYREFS,"too many references") +#endif +#ifdef ECONNREFUSED + X(ECONNREFUSED,"connection refused") +#endif +#ifdef ELOOP + X(ELOOP,"symbolic link loop") +#endif +#ifdef ENAMETOOLONG + X(ENAMETOOLONG,"file name too long") +#endif +#ifdef EHOSTDOWN + X(EHOSTDOWN,"host down") +#endif +#ifdef EHOSTUNREACH + X(EHOSTUNREACH,"host unreachable") +#endif +#ifdef ENOTEMPTY + X(ENOTEMPTY,"directory not empty") +#endif +#ifdef EPROCLIM + X(EPROCLIM,"too many processes") +#endif +#ifdef EUSERS + X(EUSERS,"too many users") +#endif +#ifdef EDQUOT + X(EDQUOT,"disk quota exceeded") +#endif +#ifdef ESTALE + X(ESTALE,"stale NFS file handle") +#endif +#ifdef EREMOTE + X(EREMOTE,"too many levels of remote in path") +#endif +#ifdef EBADRPC + X(EBADRPC,"RPC structure is bad") +#endif +#ifdef ERPCMISMATCH + X(ERPCMISMATCH,"RPC version mismatch") +#endif +#ifdef EPROGUNAVAIL + X(EPROGUNAVAIL,"RPC program unavailable") +#endif +#ifdef EPROGMISMATCH + X(EPROGMISMATCH,"program version mismatch") +#endif +#ifdef EPROCUNAVAIL + X(EPROCUNAVAIL,"bad procedure for program") +#endif +#ifdef ENOLCK + X(ENOLCK,"no locks available") +#endif +#ifdef ENOSYS + X(ENOSYS,"system call not available") +#endif +#ifdef EFTYPE + X(EFTYPE,"bad file type") +#endif +#ifdef EAUTH + X(EAUTH,"authentication error") +#endif +#ifdef ENEEDAUTH + X(ENEEDAUTH,"not authenticated") +#endif +#ifdef ENOSTR + X(ENOSTR,"not a stream device") +#endif +#ifdef ETIME + X(ETIME,"timer expired") +#endif +#ifdef ENOSR + X(ENOSR,"out of stream resources") +#endif +#ifdef ENOMSG + X(ENOMSG,"no message of desired type") +#endif +#ifdef EBADMSG + X(EBADMSG,"bad message type") +#endif +#ifdef EIDRM + X(EIDRM,"identifier removed") +#endif +#ifdef ENONET + X(ENONET,"machine not on network") +#endif +#ifdef ERREMOTE + X(ERREMOTE,"object not local") +#endif +#ifdef ENOLINK + X(ENOLINK,"link severed") +#endif +#ifdef EADV + X(EADV,"advertise error") +#endif +#ifdef ESRMNT + X(ESRMNT,"srmount error") +#endif +#ifdef ECOMM + X(ECOMM,"communication error") +#endif +#ifdef EPROTO + X(EPROTO,"protocol error") +#endif +#ifdef EMULTIHOP + X(EMULTIHOP,"multihop attempted") +#endif +#ifdef EREMCHG + X(EREMCHG,"remote address changed") +#endif + return "unknown error"; +} diff --git a/error_str=0 b/error_str=0 new file mode 100644 index 0000000..3f2616e --- /dev/null +++ b/error_str=0 @@ -0,0 +1 @@ +error_str.3 diff --git a/error_temp.3 b/error_temp.3 new file mode 100644 index 0000000..2f8229d --- /dev/null +++ b/error_temp.3 @@ -0,0 +1,27 @@ +.TH error_temp 3 +.SH NAME +error_temp \- identify soft syscall error codes +.SH SYNTAX +.B #include + +int \fBerror_temp\fP(\fIe\fR); + +int \fIe\fR; +.SH DESCRIPTION +.B error_temp +returns 1 if syscall error code +.I e +is a soft error, 0 if it is a hard error. +Normally +.I e +is +.BR errno . + +A hard error is persistent: +file not found, read-only file system, symbolic link loop, etc. + +A soft error is usually transient: +out of memory, out of disk space, I/O error, disk quota exceeded, +connection refused, host unreachable, etc. +.SH "SEE ALSO" +error(3) diff --git a/error_temp=0 b/error_temp=0 new file mode 100644 index 0000000..9b5ad0f --- /dev/null +++ b/error_temp=0 @@ -0,0 +1 @@ +error_temp.3 diff --git a/exit.h b/exit.h new file mode 100644 index 0000000..39011c8 --- /dev/null +++ b/exit.h @@ -0,0 +1,6 @@ +#ifndef EXIT_H +#define EXIT_H + +extern void _exit(); + +#endif diff --git a/ezmlm-list.1 b/ezmlm-list.1 new file mode 100644 index 0000000..38e140a --- /dev/null +++ b/ezmlm-list.1 @@ -0,0 +1,22 @@ +.TH ezmlm-list 1 +.SH NAME +ezmlm-list \- show the addresses on a mailing list +.SH SYNOPSIS +.B ezmlm-list +.I dir +.SH DESCRIPTION +.B ezmlm-list +prints the subscriber list for the mailing list stored in +.IR dir , +one address per line. + +.B WARNING: +Unless you have disabled automatic subscriptions, +the addresses in a mailing list are under the control +of a possibly malicious remote user. +.B ezmlm-list +does not strip control characters. +.SH "SEE ALSO" +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm(5) diff --git a/ezmlm-list.c b/ezmlm-list.c new file mode 100644 index 0000000..c6ec801 --- /dev/null +++ b/ezmlm-list.c @@ -0,0 +1,62 @@ +#include "stralloc.h" +#include "substdio.h" +#include "getln.h" +#include "strerr.h" +#include "error.h" +#include "readwrite.h" +#include "exit.h" +#include "open.h" + +#define FATAL "ezmlm-list: fatal: " +void die_write() +{ + strerr_die2sys(111,FATAL,"unable to write: "); +} + +char outbuf[1024]; +substdio out = SUBSTDIO_FDBUF(write,1,outbuf,sizeof(outbuf)); +char inbuf[1024]; +substdio in; + +stralloc line = {0}; + +char fn[14] = "subscribers/?"; + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + int fd; + int match; + + dir = argv[1]; + if (!dir) strerr_die1x(100,"ezmlm-list: usage: ezmlm-list dir"); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + for (fn[12] = 64;fn[12] < 64 + 53;++fn[12]) { + fd = open_read(fn); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,FATAL,"unable to open ",fn,": "); + } + else { + substdio_fdbuf(&in,read,fd,inbuf,sizeof(inbuf)); + for (;;) { + if (getln(&in,&line,&match,'\0') == -1) + strerr_die4sys(111,FATAL,"unable to read ",fn,": "); + if (!match) break; + if (line.s[str_chr(line.s,'\n')]) + strerr_die3x(111,FATAL,"newline in ",fn); + if (substdio_puts(&out,line.s + 1)) die_write(); + if (substdio_put(&out,"\n",1) == -1) die_write(); + } + } + + } + + if (substdio_flush(&out) == -1) die_write(); + _exit(0); +} diff --git a/ezmlm-list=0 b/ezmlm-list=0 new file mode 100644 index 0000000..a4c12ea --- /dev/null +++ b/ezmlm-list=0 @@ -0,0 +1 @@ +ezmlm-list.1 diff --git a/ezmlm-list=x b/ezmlm-list=x new file mode 100644 index 0000000..acaa3c7 --- /dev/null +++ b/ezmlm-list=x @@ -0,0 +1,8 @@ +strerr.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +open.a +str.a diff --git a/ezmlm-make.1 b/ezmlm-make.1 new file mode 100644 index 0000000..834feed --- /dev/null +++ b/ezmlm-make.1 @@ -0,0 +1,87 @@ +.TH ezmlm-make 1 +.SH NAME +ezmlm-make \- create a new mailing list +.SH SYNOPSIS +.B ezmlm-make +[ +.B \-aApP +] +.I dir +.I dot +.I local +.I host +.SH DESCRIPTION +.B ezmlm-make +sets up a new mailing list, +.IR local\fB@\fIhost , +along with several extra addresses to handle administrative requests. + +All mailing list information is stored in a new directory, +.IR dir . +.I dir +must be an absolute pathname, starting with a slash. + +.B ezmlm-make +sets up four +.B .qmail +files: +.IR dot , +.IR dot\fB-owner , +.IR dot\fB-return-default , +and +.IR dot\fB-default . +You should make sure that messages to +.IR local\fB@\fIhost , +.IR local\fB-owner@\fIhost , +etc. are controlled by +these +.B .qmail +files. + +Typical use of +.B ezmlm-make +by a normal user: + +.EX + ezmlm-make ~/SOS ~/.qmail-sos joe-sos isp.net +.EE + +Typical use of +.B ezmlm-make +by +.BR alias : + +.EX + ezmlm-make ~alias/SOS ~alias/.qmail-sos sos isp.net +.EE +.SH OPTIONS +.TP 5 +.B \-a +(Default.) Archived. +.B ezmlm-make +will touch +.IR dir\fB/archived , +so that +.B ezmlm-send +will archive new messages. +.TP +.B \-A +Not archived. +.TP 5 +.B \-p +(Default.) Public. +.B ezmlm-make +will touch +.IR dir\fB/public , +so that +.B ezmlm-manage +will respond to administrative requests. +.TP +.B \-P +Private. +.SH "SEE ALSO" +ezmlm-manage(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm(5) diff --git a/ezmlm-make.c b/ezmlm-make.c new file mode 100644 index 0000000..09d2b3e --- /dev/null +++ b/ezmlm-make.c @@ -0,0 +1,435 @@ +#include +#include +#include "sgetopt.h" +#include "stralloc.h" +#include "strerr.h" +#include "exit.h" +#include "readwrite.h" +#include "open.h" +#include "substdio.h" +#include "str.h" +#include "auto_bin.h" + +#define FATAL "ezmlm-make: fatal: " + +void die_usage() +{ + strerr_die1x(100,"ezmlm-make: usage: ezmlm-make [ -aApP ] dir dot local host"); +} +void die_relative() +{ + strerr_die2x(100,FATAL,"dir must start with slash"); +} +void die_newline() +{ + strerr_die2x(100,FATAL,"newlines not allowed"); +} +void die_quote() +{ + strerr_die2x(100,FATAL,"quotes not allowed"); +} +void die_nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +stralloc key = {0}; +struct timeval tv; + +void keyadd(u) +unsigned long u; +{ + char ch; + ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; + ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; + ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; + ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); +} + +void keyaddtime() +{ + gettimeofday(&tv,(struct timezone *) 0); + keyadd(tv.tv_usec); +} + +char *dir; +char *dot; +char *local; +char *host; + +stralloc dotplus = {0}; +stralloc dirplus = {0}; + +void dirplusmake(slash) +char *slash; +{ + if (!stralloc_copys(&dirplus,dir)) die_nomem(); + if (!stralloc_cats(&dirplus,slash)) die_nomem(); + if (!stralloc_0(&dirplus)) die_nomem(); +} + +void linkdotdir(dash,slash) +char *dash; +char *slash; +{ + if (!stralloc_copys(&dotplus,dot)) die_nomem(); + if (!stralloc_cats(&dotplus,dash)) die_nomem(); + if (!stralloc_0(&dotplus)) die_nomem(); + dirplusmake(slash); + if (symlink(dirplus.s,dotplus.s) == -1) + strerr_die4sys(111,FATAL,"unable to create ",dotplus.s,": "); + keyaddtime(); +} + +void dcreate(slash) +char *slash; +{ + dirplusmake(slash); + if (mkdir(dirplus.s,0755) == -1) + strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": "); + keyaddtime(); +} + +substdio ss; +char ssbuf[SUBSTDIO_OUTSIZE]; + +void fopen(slash) +char *slash; +{ + int fd; + + dirplusmake(slash); + fd = open_trunc(dirplus.s); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": "); + + substdio_fdbuf(&ss,write,fd,ssbuf,sizeof(ssbuf)); +} + +void fput(buf,len) +char *buf; +unsigned int len; +{ + if (substdio_bput(&ss,buf,len) == -1) + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); +} +void fputs(buf) +char *buf; +{ + if (substdio_bputs(&ss,buf) == -1) + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); +} + +void fclose() +{ + if (substdio_flush(&ss) == -1) + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); + if (fsync(ss.fd) == -1) + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); + if (close(ss.fd) == -1) /* NFS stupidity */ + strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); + keyaddtime(); +} + +void main(argc,argv) +int argc; +char **argv; +{ + int opt; + int flagarchived; + int flagpublic; + + keyadd(getpid()); + keyadd(getppid()); + keyadd(getuid()); + keyadd(getgid()); + gettimeofday(&tv,(struct timezone *) 0); + keyadd(tv.tv_sec); + + umask(077); + + flagarchived = 1; + flagpublic = 1; + + while ((opt = getopt(argc,argv,"aApP")) != opteof) + switch(opt) { + case 'a': flagarchived = 1; break; + case 'A': flagarchived = 0; break; + case 'p': flagpublic = 1; break; + case 'P': flagpublic = 0; break; + default: + die_usage(); + } + argv += optind; + + if (!(dir = *argv++)) die_usage(); + if (!(dot = *argv++)) die_usage(); + if (!(local = *argv++)) die_usage(); + if (!(host = *argv++)) die_usage(); + + if (dir[0] != '/') die_relative(); + if (dir[str_chr(dir,'\'')]) die_quote(); + if (dir[str_chr(dir,'\n')]) die_newline(); + if (local[str_chr(local,'\n')]) die_newline(); + if (host[str_chr(host,'\n')]) die_newline(); + + dcreate(""); + dcreate("/archive"); + dcreate("/subscribers"); + dcreate("/bounce"); + dcreate("/text"); + + + linkdotdir("-owner","/owner"); + linkdotdir("-default","/manager"); + linkdotdir("-return-default","/bouncer"); + linkdotdir("","/editor"); + + fopen("/lock"); fclose(); + fopen("/lockbounce"); fclose(); + if (flagpublic) { + fopen("/public"); fclose(); + } + if (flagarchived) { + fopen("/archived"); fclose(); + } + fopen("/num"); fputs("0\n"); fclose(); + fopen("/inhost"); fputs(host); fputs("\n"); fclose(); + fopen("/outhost"); fputs(host); fputs("\n"); fclose(); + fopen("/inlocal"); fputs(local); fputs("\n"); fclose(); + fopen("/outlocal"); fputs(local); fputs("\n"); fclose(); + + fopen("/mailinglist"); + fputs("contact "); + fputs(local); fputs("-help@"); fputs(host); fputs("; run by ezmlm\n"); + fclose(); + + fopen("/owner"); + fputs(dir); fputs("/Mailbox\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); + fputs("' || exit 0\n"); + fclose(); + + fopen("/manager"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-manage '"); fputs(dir); fputs("'\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); + fputs("' || exit 0\n"); + fclose(); + + fopen("/editor"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-reject\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-send '"); fputs(dir); fputs("'\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); + fputs("' || exit 0\n"); + fclose(); + + fopen("/bouncer"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); + fputs("' || exit 0\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-weed\n"); + fputs("|"); fputs(auto_bin); fputs("/ezmlm-return '"); fputs(dir); fputs("'\n"); + fclose(); + + fopen("/headerremove"); + fputs("\ +return-path\n\ +return-receipt-to\n\ +content-length\n\ +"); + fclose(); + + fopen("/headeradd"); + fclose(); + + + fopen("/text/top"); + fputs("Hi! This is the ezmlm program. I'm managing the\n"); + fputs(local); fputs("@"); fputs(host); fputs(" mailing list.\n\n"); + fclose(); + + fopen("/text/bottom"); + fputs("\n--- Here are the ezmlm command addresses.\n\ +\n\ +I can handle administrative requests automatically.\n\ +Just send an empty note to any of these addresses:\n\n <"); + fputs(local); fputs("-subscribe@"); fputs(host); fputs(">:\n"); + fputs(" Receive future messages sent to the mailing list.\n\n <"); + fputs(local); fputs("-unsubscribe@"); fputs(host); fputs(">:\n"); + fputs(" Stop receiving messages.\n\n <"); + fputs(local); fputs("-get.12345@"); fputs(host); fputs(">:\n"); + fputs(" Retrieve a copy of message 12345 from the archive.\n\ +\n\ +DO NOT SEND ADMINISTRATIVE REQUESTS TO THE MAILING LIST!\n\ +If you do, I won't see them, and subscribers will yell at you.\n\ +\n\ +To specify God@heaven.af.mil as your subscription address, send mail\n\ +to <"); + fputs(local); fputs("-subscribe-God=heaven.af.mil@"); fputs(host); + fputs(">.\n\ +I'll send a confirmation message to that address; when you receive that\n\ +message, simply reply to it to complete your subscription.\n\ +\n"); + fputs("\n--- Below this line is a copy of the request I received.\n\n"); + fclose(); + + fopen("/text/sub-confirm"); + fputs("To confirm that you would like\n\ +\n\ +!A\n\ +\n\ +added to this mailing list, please send an empty reply to this address:\n\ +\n\ +!R\n\ +\n\ +Your mailer should have a Reply feature that uses this address automatically.\n\ +\n\ +This confirmation serves two purposes. First, it verifies that I am able\n\ +to get mail through to you. Second, it protects you in case someone\n\ +forges a subscription request in your name.\n\ +\n"); + fclose(); + + fopen("/text/unsub-confirm"); + fputs("To confirm that you would like\n\ +\n\ +!A\n\ +\n\ +removed from this mailing list, please send an empty reply to this address:\n\ +\n\ +!R\n\ +\n\ +Your mailer should have a Reply feature that uses this address automatically.\n\ +\n\ +I haven't checked whether your address is currently on the mailing list.\n\ +To see what address you used to subscribe, look at the messages you are\n\ +receiving from the mailing list. Each message has your address hidden\n\ +inside its return path; for example, God@heaven.af.mil receives messages\n\ +with return path ...-God=heaven.af.mil.\n\ +\n"); + fclose(); + + fopen("/text/sub-ok"); + fputs("Acknowledgment: I have added the address\n\ +\n\ +!A\n\ +\n\ +to this mailing list.\n\ +\n"); + fclose(); + + fopen("/text/unsub-ok"); + fputs("Acknowledgment: I have removed the address\n\ +\n\ +!A\n\ +\n\ +from this mailing list.\n\ +\n"); + fclose(); + + fopen("/text/sub-nop"); + fputs("Acknowledgment: The address\n\ +\n\ +!A\n\ +\n\ +is on this mailing list.\n\ +\n"); + fclose(); + + fopen("/text/unsub-nop"); + fputs("Acknowledgment: The address\n\ +\n\ +!A\n\ +\n\ +is not on this mailing list.\n\ +\n"); + fclose(); + + fopen("/text/sub-bad"); + fputs("Oops, that confirmation number appears to be invalid.\n\ +\n\ +The most common reason for invalid numbers is expiration. I have to\n\ +receive confirmation of each request within ten days.\n\ +\n\ +I've set up a new confirmation number. To confirm that you would like\n\ +\n\ +!A\n\ +\n\ +added to this mailing list, please send an empty reply to this address:\n\ +\n\ +!R\n\ +\n\ +Sorry for the trouble.\n\ +\n"); + fclose(); + + fopen("/text/unsub-bad"); + fputs("Oops, that confirmation number appears to be invalid.\n\ +\n\ +The most common reason for invalid numbers is expiration. I have to\n\ +receive confirmation of each request within ten days.\n\ +\n\ +I've set up a new confirmation number. To confirm that you would like\n\ +\n\ +!A\n\ +\n\ +removed from this mailing list, please send an empty reply to this address:\n\ +\n\ +!R\n\ +\n\ +Sorry for the trouble.\n\ +\n"); + fclose(); + + fopen("/text/get-bad"); + fputs("Sorry, I don't see that message.\n\n"); + fclose(); + + fopen("/text/bounce-bottom"); + fputs("\n\ +--- Below this line is a copy of the bounce message I received.\n\n"); + fclose(); + + fopen("/text/bounce-warn"); + fputs("\n\ +Messages to you seem to have been bouncing. I've attached a copy of\n\ +the first bounce message I received.\n\ +\n\ +If this message bounces too, I will send you a probe. If the probe bounces,\n\ +I will remove your address from the mailing list, without further notice.\n\ +\n"); + fclose(); + + fopen("/text/bounce-probe"); + fputs("\n\ +Messages to you seem to have been bouncing. I sent you a warning\n\ +message, but it bounced. I've attached a copy of the bounce message.\n\ +\n\ +This is a probe to check whether your address is reachable. If this\n\ +probe bounces, I will remove your address from the mailing list, without\n\ +further notice.\n\ +\n"); + fclose(); + + fopen("/text/bounce-num"); + fputs("\n\ +I've kept a list of which messages bounced from your address. Copies of\n\ +these messages may be in the archive. To get message 12345 from the\n\ +archive, send an empty note to "); + fputs(local); fputs("-get.12345@"); fputs(host); fputs(".\n\ +Here are the message numbers:\n\ +\n"); + fclose(); + + fopen("/text/help"); + fputs("\ +This is a generic help message. The message I received wasn't sent to\n\ +any of my command addresses.\n\ +\n"); + fclose(); + + fopen("/key"); + fput(key.s,key.len); + fclose(); + + _exit(0); +} diff --git a/ezmlm-make=0 b/ezmlm-make=0 new file mode 100644 index 0000000..d49ded8 --- /dev/null +++ b/ezmlm-make=0 @@ -0,0 +1 @@ +ezmlm-make.1 diff --git a/ezmlm-make=x b/ezmlm-make=x new file mode 100644 index 0000000..1295af4 --- /dev/null +++ b/ezmlm-make=x @@ -0,0 +1,9 @@ +auto_bin.o +open.a +getopt.a +substdio.a +strerr.a +stralloc.a +alloc.a +error.a +str.a diff --git a/ezmlm-manage.1 b/ezmlm-manage.1 new file mode 100644 index 0000000..a68438f --- /dev/null +++ b/ezmlm-manage.1 @@ -0,0 +1,129 @@ +.TH ezmlm-manage 1 +.SH NAME +ezmlm-manage \- automatically manage a mailing list +.SH SYNOPSIS +.B ezmlm-manage +.I dir +.SH DESCRIPTION +.B ezmlm-manage +handles administrative requests for the mailing list +stored in +.IR dir . + +.B ezmlm-manage +is normally invoked from a +.B .qmail +file. +It reads a mail message from its standard input, +and a mail envelope from the +.BR SENDER , +.BR LOCAL , +and +.BR HOST +environment variables. + +.B ezmlm-manage +expects +.B LOCAL +to be of the form +.IR list\fB-\fIaction\fB-\fIbox\fB=\fIdomain . +Here +.I list +is the first line of +.IR dir\fB/inlocal , +.I action +is a request, +and +.I box\fB@\fIdomain +is the target of the request. +.B ezmlm-manage +sends a response to the target. +It attaches the original message to the end of its response. + +.B LOCAL +may instead be of the form +.IR list\fB-\fIaction . +Then the envelope sender +is used as the target. + +.B ezmlm-manage +expects +.B HOST +to match the first line of +.IR dir\fB/inhost . + +.B ezmlm-manage +copies +.I dir\fB/mailinglist +into a +.B Mailing-List +field in its response. +If the incoming message has a +.B Mailing-List +field, +.B ezmlm-manage +refuses to respond. +.B ezmlm-manage +also refuses to respond to bounce messages. +.SH SUBSCRIPTIONS +If +.I action +is +.BR sc.\fIcookie , +where +.I cookie +is an appropriate code +(depending on the target, the approximate time, and other factors), +.B ezmlm-manage +adds the target to the mailing list. + +If +.I action +is +.BR subscribe , +.B ezmlm-manage +does not subscribe the target, +but it identifies the right +.BR sc.\fIcookie +address in its response. + +This confirmation mechanism +(1) verifies that the target is reachable +and +(2) protects the target against forged subscription requests. + +Actions of +.B uc.\fIcookie +and +.B unsubscribe +are used in the same way to delete the target from the mailing list. + +If +.I dir\fB/public +does not exist, +.B ezmlm-manage +rejects all subscription and unsubscription attempts. +.SH "ARCHIVE RETRIEVALS" +If +.I action +is +.BR get.\fInum , +.B ezmlm-manage +sends back message +.I num +from +.IR dir\fB/archive . + +If +.I dir\fB/public +does not exist, +.B ezmlm-manage +rejects all archive retrieval attempts. +.SH "SEE ALSO" +ezmlm-make(1), +ezmlm-return(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm(5), +qmail-command(8) diff --git a/ezmlm-manage.c b/ezmlm-manage.c new file mode 100644 index 0000000..d40ba0f --- /dev/null +++ b/ezmlm-manage.c @@ -0,0 +1,403 @@ +#include +#include +#include "error.h" +#include "stralloc.h" +#include "str.h" +#include "env.h" +#include "sig.h" +#include "slurp.h" +#include "getconf.h" +#include "strerr.h" +#include "byte.h" +#include "getln.h" +#include "case.h" +#include "qmail.h" +#include "substdio.h" +#include "readwrite.h" +#include "seek.h" +#include "quote.h" +#include "datetime.h" +#include "now.h" +#include "date822fmt.h" +#include "fmt.h" +#include "subscribe.h" +#include "cookie.h" + +#define FATAL "ezmlm-manage: fatal: " +void die_usage() { strerr_die1x(100,"ezmlm-manage: usage: ezmlm-manage dir"); } +void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } +void die_badaddr() +{ + strerr_die2x(100,FATAL,"I do not accept messages at this address (#5.1.1)"); +} + +stralloc inhost = {0}; +stralloc outhost = {0}; +stralloc inlocal = {0}; +stralloc outlocal = {0}; +stralloc key = {0}; +stralloc mailinglist = {0}; + +datetime_sec when; +struct datetime dt; + +char strnum[FMT_ULONG]; +char date[DATE822FMT]; +char hash[COOKIE]; +datetime_sec hashdate; +stralloc target = {0}; +stralloc confirm = {0}; +stralloc line = {0}; +stralloc quoted = {0}; + +int hashok(action) +char *action; +{ + char *x; + unsigned long u; + + x = action + 4; + x += scan_ulong(x,&u); + hashdate = u; + if (hashdate > when) return 0; + if (hashdate < when - 1000000) return 0; + + u = hashdate; + strnum[fmt_ulong(strnum,u)] = 0; + cookie(hash,key.s,key.len,strnum,target.s,action + 1); + + if (*x == '.') ++x; + if (str_len(x) != COOKIE) return 0; + return byte_equal(hash,COOKIE,x); +} + +struct qmail qq; +int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len; +{ + qmail_put(&qq,buf,len); + return len; +} +char qqbuf[1]; +substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf)); + +char inbuf[1024]; +substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf)); +substdio ssin2 = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf)); + +substdio sstext; +char textbuf[1024]; + +void copy(fn) +char *fn; +{ + int fd; + int match; + + fd = open_read(fn); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to open ",fn,": "); + + substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); + for (;;) { + if (getln(&sstext,&line,&match,'\n') == -1) + strerr_die4sys(111,FATAL,"unable to read ",fn,": "); + + if (match) + if (line.s[0] == '!') { + if (line.s[1] == 'R') { + qmail_puts(&qq," "); + qmail_puts(&qq,confirm.s); + qmail_puts(&qq,"\n"); + continue; + } + if (line.s[1] == 'A') { + qmail_puts(&qq," "); + qmail_puts(&qq,target.s); + qmail_puts(&qq,"\n"); + continue; + } + } + + qmail_put(&qq,line.s,line.len); + + if (!match) + break; + } + + close(fd); +} + +stralloc mydtline = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *sender; + char *host; + char *local; + char *action; + int fd; + int i; + int flagconfirm; + int flaghashok; + int flaggoodfield; + int match; + + umask(022); + sig_pipeignore(); + when = now(); + + dir = argv[1]; + if (!dir) die_usage(); + + sender = env_get("SENDER"); + if (!sender) strerr_die2x(100,FATAL,"SENDER not set"); + local = env_get("LOCAL"); + if (!local) strerr_die2x(100,FATAL,"LOCAL not set"); + host = env_get("HOST"); + if (!host) strerr_die2x(100,FATAL,"HOST not set"); + + if (!*sender) + strerr_die2x(100,FATAL,"I don't reply to bounce messages (#5.7.2)"); + if (!sender[str_chr(sender,'@')]) + strerr_die2x(100,FATAL,"I don't reply to senders without host names (#5.7.2)"); + if (str_equal(sender,"#@[]")) + strerr_die2x(100,FATAL,"I don't reply to bounce messages (#5.7.2)"); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + switch(slurp("key",&key,32)) { + case -1: + strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: "); + case 0: + strerr_die3x(100,FATAL,dir,"/key does not exist"); + } + getconf_line(&mailinglist,"mailinglist",1,FATAL,dir); + getconf_line(&inhost,"inhost",1,FATAL,dir); + getconf_line(&inlocal,"inlocal",1,FATAL,dir); + getconf_line(&outhost,"outhost",1,FATAL,dir); + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + + if (inhost.len != str_len(host)) die_badaddr(); + if (case_diffb(inhost.s,inhost.len,host)) die_badaddr(); + if (inlocal.len > str_len(local)) die_badaddr(); + if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr(); + + action = local + inlocal.len; + + switch(slurp("public",&line,1)) { + case -1: + strerr_die4sys(111,FATAL,"unable to read ",dir,"/public: "); + case 0: + strerr_die2x(100,FATAL,"sorry, I've been told to reject all requests (#5.7.2)"); + } + + if (!stralloc_copys(&target,sender)) die_nomem(); + if (action[0]) { + i = 1 + str_chr(action + 1,'-'); + if (action[i]) { + action[i] = 0; + if (!stralloc_copys(&target,action + i + 1)) die_nomem(); + i = byte_rchr(target.s,target.len,'='); + if (i < target.len) + target.s[i] = '@'; + } + } + if (!stralloc_0(&target)) die_nomem(); + if (!stralloc_copys(&confirm,"")) die_nomem(); + + if (qmail_open(&qq) == -1) + strerr_die2sys(111,FATAL,"unable to run qmail-queue: "); + + qmail_puts(&qq,"Mailing-List: "); + qmail_put(&qq,mailinglist.s,mailinglist.len); + qmail_puts(&qq,"\nDate: "); + datetime_tai(&dt,when); + qmail_put(&qq,date,date822fmt(date,&dt)); + qmail_puts(&qq,"Message-ID: <"); + qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) when)); + qmail_puts(&qq,"."); + qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) getpid())); + qmail_puts(&qq,".ezmlm@"); + qmail_put(&qq,outhost.s,outhost.len); + qmail_puts(&qq,">\nFrom: "); + if (!quote("ed,&outlocal)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,"-help@"); + qmail_put(&qq,outhost.s,outhost.len); + qmail_puts(&qq,"\nTo: "); + if (!quote2("ed,target.s)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,"\n"); + + flaghashok = 1; + if (str_start(action,"-sc.")) flaghashok = hashok(action); + if (str_start(action,"-uc.")) flaghashok = hashok(action); + + flagconfirm = 0; + if (str_equal(action,"-subscribe")) flagconfirm = 1; + if (str_equal(action,"-unsubscribe")) flagconfirm = 1; + if (!flaghashok) flagconfirm = 1; + + if (flagconfirm) { + strnum[fmt_ulong(strnum,(unsigned long) when)] = 0; + cookie(hash,key.s,key.len,strnum,target.s,action + 1); + if (!stralloc_copy(&confirm,&outlocal)) die_nomem(); + if (!stralloc_cats(&confirm,"-")) die_nomem(); + if (!stralloc_catb(&confirm,action + 1,1)) die_nomem(); + if (!stralloc_cats(&confirm,"c.")) die_nomem(); + if (!stralloc_cats(&confirm,strnum)) die_nomem(); + if (!stralloc_cats(&confirm,".")) die_nomem(); + if (!stralloc_catb(&confirm,hash,COOKIE)) die_nomem(); + if (!stralloc_cats(&confirm,"-")) die_nomem(); + i = str_rchr(target.s,'@'); + if (!stralloc_catb(&confirm,target.s,i)) die_nomem(); + if (target.s[i]) { + if (!stralloc_cats(&confirm,"=")) die_nomem(); + if (!stralloc_cats(&confirm,target.s + i + 1)) die_nomem(); + } + if (!stralloc_cats(&confirm,"@")) die_nomem(); + if (!stralloc_cat(&confirm,&outhost)) die_nomem(); + if (!stralloc_0(&confirm)) die_nomem(); + + qmail_puts(&qq,"Reply-To: "); + if (!quote2("ed,confirm.s)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,"\n"); + } + if (!stralloc_0(&confirm)) die_nomem(); + + qmail_puts(&qq,"Subject: ezmlm response\n"); + + if (!stralloc_copys(&mydtline,"Delivered-To: responder for ")) die_nomem(); + if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem(); + if (!stralloc_cats(&mydtline,"@")) die_nomem(); + if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem(); + if (!stralloc_cats(&mydtline,"\n")) die_nomem(); + + qmail_put(&qq,mydtline.s,mydtline.len); + + flaggoodfield = 0; + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + if (!match) break; + if (line.len == 1) break; + if ((line.s[0] != ' ') && (line.s[0] != '\t')) { + flaggoodfield = 0; + if (case_startb(line.s,line.len,"mailing-list:")) + strerr_die2x(100,FATAL,"incoming message has Mailing-List (#5.7.2)"); + if (line.len == mydtline.len) + if (byte_equal(line.s,line.len,mydtline.s)) + strerr_die2x(100,FATAL,"this message is looping: it already has my Delivered-To line (#5.4.6)"); + if (case_startb(line.s,line.len,"delivered-to:")) + flaggoodfield = 1; + if (case_startb(line.s,line.len,"received:")) + flaggoodfield = 1; + } + if (flaggoodfield) + qmail_put(&qq,line.s,line.len); + } + if (seek_begin(0) == -1) + strerr_die2sys(111,FATAL,"unable to seek input: "); + + qmail_puts(&qq,"\n"); + copy("text/top"); + if (str_equal(action,"-subscribe")) + copy("text/sub-confirm"); + else if (str_equal(action,"-unsubscribe")) + copy("text/unsub-confirm"); + else if (str_start(action,"-sc.")) { + if (!flaghashok) + copy("text/sub-bad"); + else + switch(subscribe(target.s,1)) { + case -1: strerr_die1(111,FATAL,&subscribe_err); + case -2: strerr_die1(100,FATAL,&subscribe_err); + case 1: log("+",target.s); copy("text/sub-ok"); break; + default: copy("text/sub-nop"); break; + } + } + else if (str_start(action,"-uc.")) { + if (!flaghashok) + copy("text/unsub-bad"); + else + switch(subscribe(target.s,0)) { + case -1: strerr_die1(111,FATAL,&subscribe_err); + case -2: strerr_die1(100,FATAL,&subscribe_err); + case 1: log("-",target.s); copy("text/unsub-ok"); break; + default: copy("text/unsub-nop"); break; + } + } + else if (str_start(action,"-get.")) { + unsigned long u; + struct stat st; + char ch; + int r; + + scan_ulong(action + 5,&u); + + if (!stralloc_copys(&line,"archive/")) die_nomem(); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,u / 100))) die_nomem(); + if (!stralloc_cats(&line,"/")) die_nomem(); + if (!stralloc_catb(&line,strnum,fmt_uint0(strnum,(unsigned int) (u % 100),2))) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + + fd = open_read(line.s); + if (fd == -1) + if (errno != error_noent) + strerr_die4sys(111,FATAL,"unable to open ",line.s,": "); + else + copy("text/get-bad"); + else { + if (fstat(fd,&st) == -1) + copy("text/get-bad"); + else if (!(st.st_mode & 0100)) + copy("text/get-bad"); + else { + substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); + qmail_puts(&qq,"> "); + for (;;) { + r = substdio_get(&sstext,&ch,1); + if (r == -1) strerr_die4sys(111,FATAL,"unable to read ",line.s,": "); + if (r == 0) break; + qmail_put(&qq,&ch,1); + if (ch == '\n') qmail_puts(&qq,"> "); + } + qmail_puts(&qq,"\n"); + } + close(fd); + } + } + else + copy("text/help"); + + copy("text/bottom"); + + qmail_puts(&qq,"Return-Path: <"); + if (!quote2("ed,sender)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,">\n"); + if (substdio_copy(&ssqq,&ssin2) != 0) + strerr_die2sys(111,FATAL,"unable to read input: "); + + if (!stralloc_copy(&line,&outlocal)) die_nomem(); + if (!stralloc_cats(&line,"-return-@")) die_nomem(); + if (!stralloc_cat(&line,&outhost)) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + qmail_from(&qq,line.s); + + qmail_to(&qq,target.s); + + switch(qmail_close(&qq)) { + case 0: + strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; + strerr_die2x(0,"ezmlm-manage: info: qp ",strnum); + default: + /* don't worry about undoing actions; everything is idempotent */ + strerr_die2x(111,FATAL,"temporary qmail-queue error"); + } +} diff --git a/ezmlm-manage=0 b/ezmlm-manage=0 new file mode 100644 index 0000000..844327b --- /dev/null +++ b/ezmlm-manage=0 @@ -0,0 +1 @@ +ezmlm-manage.1 diff --git a/ezmlm-manage=x b/ezmlm-manage=x new file mode 100644 index 0000000..c51b445 --- /dev/null +++ b/ezmlm-manage=x @@ -0,0 +1,29 @@ +auto_qmail.o +getconf.o +subscribe.o +log.o +cookie.o +now.o +datetime.o +date822fmt.o +slurpclose.o +slurp.o +qmail.o +quote.o +surf.a +getln.a +env.a +sig.a +strerr.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +fs.a +case.a +open.a +seek.a +wait.a +lock.a +fd.a diff --git a/ezmlm-reject.1 b/ezmlm-reject.1 new file mode 100644 index 0000000..cb8cb7a --- /dev/null +++ b/ezmlm-reject.1 @@ -0,0 +1,32 @@ +.TH ezmlm-reject 1 +.SH NAME +ezmlm-reject \- reject messages unsuitable for distribution +.SH SYNOPSIS +.B ezmlm-reject +[ +.B \-cCsS +] +.SH DESCRIPTION +.B ezmlm-reject +reads a mail message from its standard input. +It rejects the message if it sees something it doesn't like. +.SH OPTIONS +.TP +.B \-c +(Default.) +Commands are not permitted in the Subject line. +A Subject line consisting solely of HELP, SUBSCRIBE, or UNSUBSCRIBE +is rejected. +.TP +.B \-C +Commands are permitted in the subject line. +.TP +.B \-s +(Default.) +A nonempty Subject line is required. +.TP +.B \-S +A Subject line is not required. +.SH "SEE ALSO" +ezmlm-send(1), +qmail-command(8) diff --git a/ezmlm-reject.c b/ezmlm-reject.c new file mode 100644 index 0000000..ffeea99 --- /dev/null +++ b/ezmlm-reject.c @@ -0,0 +1,82 @@ +#include "strerr.h" +#include "substdio.h" +#include "readwrite.h" +#include "stralloc.h" +#include "getln.h" +#include "sgetopt.h" + +int flagrejectcommands = 1; +int flagneedsubject = 1; + +int flaghavesubject = 0; +int flaghavecommand = 0; + +char buf0[256]; +substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0)); +stralloc line = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + int opt; + char *x; + int len; + int match; + + while ((opt = getopt(argc,argv,"cCsS")) != opteof) + switch(opt) { + case 'c': flagrejectcommands = 1; break; + case 'C': flagrejectcommands = 0; break; + case 's': flagneedsubject = 1; break; + case 'S': flagneedsubject = 0; break; + default: + strerr_die1x(100,"ezmlm-reject: usage: ezmlm-reject [ -cCsS ]"); + } + + for (;;) { + if (getln(&ss0,&line,&match,'\n') == -1) + strerr_die2sys(111,"ezmlm-reject: fatal: ","unable to read input: "); + if (!match) break; + if (line.len == 1) break; + + x = line.s; len = line.len - 1; + while (len && ((x[len - 1] == ' ') || (x[len - 1] == '\t'))) --len; + + if (case_startb(x,len,"subject:")) { + x += 8; len -= 8; + while (len && ((*x == ' ') || (*x == '\t'))) { ++x; --len; } + if (len) { + flaghavesubject = 1; + + if (len == 4) + if (!case_diffb("help",4,x)) + flaghavecommand = 1; + + if (len == 9) + if (!case_diffb("subscribe",9,x)) + flaghavecommand = 1; + + if (len == 11) + if (!case_diffb("unsubscribe",11,x)) + flaghavecommand = 1; + } + } + } + + if (flagneedsubject && !flaghavesubject) + strerr_die1x(100,"\ +ezmlm-reject: fatal: I need a nonempty Subject line in every message.\n\ +If you are trying to subscribe or unsubscribe, WRONG ADDRESS!\n\ +Do not send administrative requests to the mailing list.\n\ +Send an empty message to ...-help@... for automated assistance."); + + if (flagrejectcommands && flaghavecommand) + strerr_die1x(100,"\ +ezmlm-reject: fatal: Your Subject line looks like a command word.\n\ +If you are trying to subscribe or unsubscribe, WRONG ADDRESS!\n\ +Do not send administrative requests to the mailing list.\n\ +Send an empty message to ...-help@... for automated assistance."); + + _exit(0); +} diff --git a/ezmlm-reject=0 b/ezmlm-reject=0 new file mode 100644 index 0000000..92fa5a2 --- /dev/null +++ b/ezmlm-reject=0 @@ -0,0 +1 @@ +ezmlm-reject.1 diff --git a/ezmlm-reject=x b/ezmlm-reject=x new file mode 100644 index 0000000..166f429 --- /dev/null +++ b/ezmlm-reject=x @@ -0,0 +1,9 @@ +getln.a +strerr.a +substdio.a +error.a +stralloc.a +alloc.a +str.a +getopt.a +case.a diff --git a/ezmlm-return.1 b/ezmlm-return.1 new file mode 100644 index 0000000..3f84989 --- /dev/null +++ b/ezmlm-return.1 @@ -0,0 +1,71 @@ +.TH ezmlm-return 1 +.SH NAME +ezmlm-return \- handle mailing list bounces +.SH SYNOPSIS +.B ezmlm-return +.I dir +.SH DESCRIPTION +.B ezmlm-return +handles bounces for the mailing list +stored in +.IR dir . + +.B ezmlm-return +is normally invoked from a +.B .qmail +file. +It reads a mail message from its standard input, +and a mail envelope from the +.BR SENDER , +.BR LOCAL , +and +.BR HOST +environment variables. +.SH ADDRESSES +.B ezmlm-return +handles mail sent to any of the following addresses: +.TP +.I local\fB\-return\- +Trash. +A help message or subscription acknowledgment bounced. +.TP +.I local\fB\-return\-\fImsg\fB\-\fIbox\fB=\fIdomain +Distribution bounce. +Message number +.I msg +was lost on the way to +.IR box\fB@\fIdomain . +.TP +.I local\fB\-return\-\fImsg\fB\- +Pre-VERP distribution bounce, in QSBMF format. +Message number +.I msg +was lost on the way to one or more addresses; +.B ezmlm-return +will parse the bounce to figure out the addresses. +.TP +.I local\fB\-return\-warn\-\fIcookie\fB-\fIbox\fB=\fIdomain +Warning bounce. +A warning message from +.B ezmlm-warn +bounced. +.TP +.I local\fB\-return\-probe\-\fIcookie\fB-\fIbox\fB=\fIdomain +Probe bounce. +A probe from +.B ezmlm-warn +bounced. +.B ezmlm-return +will remove +.I box\fB@\fIdomain +from the mailing list. +.SH "SEE ALSO" +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm-warn(1), +ezmlm-weed(1), +ezmlm(5), +qmail-command(8) diff --git a/ezmlm-return.c b/ezmlm-return.c new file mode 100644 index 0000000..3bc2421 --- /dev/null +++ b/ezmlm-return.c @@ -0,0 +1,364 @@ +#include "stralloc.h" +#include "str.h" +#include "env.h" +#include "sig.h" +#include "slurp.h" +#include "getconf.h" +#include "strerr.h" +#include "byte.h" +#include "case.h" +#include "getln.h" +#include "substdio.h" +#include "error.h" +#include "quote.h" +#include "readwrite.h" +#include "fmt.h" +#include "now.h" +#include "cookie.h" +#include "subscribe.h" +#include "issub.h" + +#define FATAL "ezmlm-return: fatal: " +void die_usage() { strerr_die1x(100,"ezmlm-return: usage: ezmlm-return dir"); } +void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } +void die_badaddr() +{ + strerr_die2x(100,FATAL,"I do not accept messages at this address (#5.1.1)"); +} +void die_trash() +{ + strerr_die1x(0,"ezmlm-return: info: trash address"); +} + +char outbuf[1024]; +substdio ssout; +char inbuf[1024]; +substdio ssin; + +char strnum[FMT_ULONG]; +char hash[COOKIE]; +char hashcopy[COOKIE]; +unsigned long cookiedate; +stralloc fndate = {0}; +stralloc fndatenew = {0}; +stralloc fnhash = {0}; +stralloc fnhashnew = {0}; + +stralloc quoted = {0}; +char *sender; + +void die_hashnew() +{ strerr_die4sys(111,FATAL,"unable to write ",fnhashnew.s,": "); } +void die_datenew() +{ strerr_die4sys(111,FATAL,"unable to write ",fndatenew.s,": "); } +void die_msgin() +{ strerr_die2sys(111,FATAL,"unable to read input: "); } + +void dowit(addr,when,bounce) +char *addr; +unsigned long when; +stralloc *bounce; +{ + int fd; + + if (!issub(addr)) return; + + if (!stralloc_copys(&fndate,"bounce/w")) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem(); + if (!stralloc_cats(&fndate,".")) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); + if (!stralloc_0(&fndate)) die_nomem(); + if (!stralloc_copy(&fndatenew,&fndate)) die_nomem(); + fndatenew.s[7] = 'W'; + + fd = open_trunc(fndatenew.s); + if (fd == -1) die_datenew(); + substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); + if (substdio_puts(&ssout,addr) == -1) die_datenew(); + if (substdio_put(&ssout,"",1) == -1) die_datenew(); + if (substdio_puts(&ssout,"Return-Path: <") == -1) die_datenew(); + if (!quote2("ed,sender)) die_nomem(); + if (substdio_put(&ssout,quoted.s,quoted.len) == -1) die_datenew(); + if (substdio_puts(&ssout,">\n") == -1) die_datenew(); + if (substdio_put(&ssout,bounce->s,bounce->len) == -1) die_datenew(); + if (substdio_flush(&ssout) == -1) die_datenew(); + if (fsync(fd) == -1) die_datenew(); + if (close(fd) == -1) die_datenew(); /* NFS stupidity */ + + if (rename(fndatenew.s,fndate.s) == -1) + strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": "); +} + +void doit(addr,msgnum,when,bounce) +char *addr; +unsigned long msgnum; +unsigned long when; +stralloc *bounce; +{ + int fd; + int fdnew; + + if (!issub(addr)) return; + + if (!stralloc_copys(&fndate,"bounce/d")) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem(); + if (!stralloc_cats(&fndate,".")) die_nomem(); + if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); + if (!stralloc_0(&fndate)) die_nomem(); + if (!stralloc_copy(&fndatenew,&fndate)) die_nomem(); + fndatenew.s[7] = 'D'; + + fd = open_trunc(fndatenew.s); + if (fd == -1) die_datenew(); + substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); + if (substdio_puts(&ssout,addr) == -1) die_datenew(); + if (substdio_put(&ssout,"",1) == -1) die_datenew(); + if (substdio_puts(&ssout,"Return-Path: <") == -1) die_datenew(); + if (!quote2("ed,sender)) die_nomem(); + if (substdio_put(&ssout,quoted.s,quoted.len) == -1) die_datenew(); + if (substdio_puts(&ssout,">\n") == -1) die_datenew(); + if (substdio_put(&ssout,bounce->s,bounce->len) == -1) die_datenew(); + if (substdio_flush(&ssout) == -1) die_datenew(); + if (fsync(fd) == -1) die_datenew(); + if (close(fd) == -1) die_datenew(); /* NFS stupidity */ + + cookie(hash,"",0,"",addr,""); + if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem(); + if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem(); + if (!stralloc_0(&fnhash)) die_nomem(); + if (!stralloc_copy(&fnhashnew,&fnhash)) die_nomem(); + fnhashnew.s[7] = 'H'; + + fdnew = open_trunc(fnhashnew.s); + if (fdnew == -1) die_hashnew(); + substdio_fdbuf(&ssout,write,fdnew,outbuf,sizeof(outbuf)); + + fd = open_read(fnhash.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,FATAL,"unable to read ",fnhash.s,": "); + if (rename(fndatenew.s,fndate.s) == -1) + strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": "); + } + else { + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + switch(substdio_copy(&ssout,&ssin)) { + case -2: die_msgin(); + case -3: die_hashnew(); + } + close(fd); + if (unlink(fndatenew.s) == -1) + strerr_die4sys(111,FATAL,"unable to unlink ",fndatenew.s,": "); + } + if (substdio_puts(&ssout," ") == -1) die_hashnew(); + if (substdio_put(&ssout,strnum,fmt_ulong(strnum,msgnum)) == -1) die_hashnew(); + if (substdio_puts(&ssout,"\n") == -1) die_hashnew(); + if (substdio_flush(&ssout) == -1) die_hashnew(); + if (fsync(fdnew) == -1) die_hashnew(); + if (close(fdnew) == -1) die_hashnew(); /* NFS stupidity */ + + if (rename(fnhashnew.s,fnhash.s) == -1) + strerr_die6sys(111,FATAL,"unable to rename ",fnhashnew.s," to ",fnhash.s,": "); +} + +stralloc bounce = {0}; +stralloc line = {0}; +stralloc header = {0}; +stralloc intro = {0}; +stralloc failure = {0}; +stralloc paragraph = {0}; +int flaghaveheader; +int flaghaveintro; + +stralloc key = {0}; +stralloc inhost = {0}; +stralloc outhost = {0}; +stralloc inlocal = {0}; +stralloc outlocal = {0}; + +char msginbuf[1024]; +substdio ssmsgin; + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *host; + char *local; + char *action; + unsigned long msgnum; + unsigned long cookiedate; + unsigned long when; + int match; + int i; + int fdlock; + + umask(022); + sig_pipeignore(); + when = (unsigned long) now(); + + dir = argv[1]; + if (!dir) die_usage(); + + sender = env_get("SENDER"); + if (!sender) strerr_die2x(100,FATAL,"SENDER not set"); + local = env_get("LOCAL"); + if (!local) strerr_die2x(100,FATAL,"LOCAL not set"); + host = env_get("HOST"); + if (!host) strerr_die2x(100,FATAL,"HOST not set"); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + switch(slurp("key",&key,32)) { + case -1: + strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: "); + case 0: + strerr_die3x(100,FATAL,dir,"/key does not exist"); + } + getconf_line(&inhost,"inhost",1,FATAL,dir); + getconf_line(&inlocal,"inlocal",1,FATAL,dir); + getconf_line(&outhost,"outhost",1,FATAL,dir); + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + + if (inhost.len != str_len(host)) die_badaddr(); + if (case_diffb(inhost.s,inhost.len,host)) die_badaddr(); + if (inlocal.len > str_len(local)) die_badaddr(); + if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr(); + + action = local + inlocal.len; + + if (!str_start(action,"-return-")) die_badaddr(); + action += 8; + + if (!*action) die_trash(); + + if (str_start(action,"probe-")) { + action += 6; + action += scan_ulong(action,&cookiedate); + if (now() - cookiedate > 3000000) die_trash(); + if (*action++ != '.') die_trash(); + i = str_chr(action,'-'); + if (i != COOKIE) die_trash(); + byte_copy(hashcopy,COOKIE,action); + action += COOKIE; + if (*action++ != '-') die_trash(); + i = str_rchr(action,'='); + if (!stralloc_copyb(&line,action,i)) die_nomem(); + if (action[i]) { + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cats(&line,action + i + 1)) die_nomem(); + } + if (!stralloc_0(&line)) die_nomem(); + strnum[fmt_ulong(strnum,cookiedate)] = 0; + cookie(hash,key.s,key.len,strnum,line.s,"P"); + if (byte_diff(hash,COOKIE,hashcopy)) die_trash(); + + if (subscribe(line.s,0) == 1) log("-probe",line.s); + _exit(0); + } + + fdlock = open_append("lockbounce"); + if (fdlock == -1) + strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: "); + if (lock_ex(fdlock) == -1) + strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: "); + + if (str_start(action,"warn-")) { + action += 5; + action += scan_ulong(action,&cookiedate); + if (now() - cookiedate > 3000000) die_trash(); + if (*action++ != '.') die_trash(); + i = str_chr(action,'-'); + if (i != COOKIE) die_trash(); + byte_copy(hashcopy,COOKIE,action); + action += COOKIE; + if (*action++ != '-') die_trash(); + i = str_rchr(action,'='); + if (!stralloc_copyb(&line,action,i)) die_nomem(); + if (action[i]) { + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cats(&line,action + i + 1)) die_nomem(); + } + if (!stralloc_0(&line)) die_nomem(); + strnum[fmt_ulong(strnum,cookiedate)] = 0; + cookie(hash,key.s,key.len,strnum,line.s,"W"); + if (byte_diff(hash,COOKIE,hashcopy)) die_trash(); + + if (slurpclose(0,&bounce,1024) == -1) die_msgin(); + dowit(line.s,when,&bounce); + _exit(0); + } + + action += scan_ulong(action,&msgnum); + if (*action != '-') die_badaddr(); + ++action; + + if (*action) { + if (slurpclose(0,&bounce,1024) == -1) die_msgin(); + + i = str_rchr(action,'='); + if (!stralloc_copyb(&line,action,i)) die_nomem(); + if (action[i]) { + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cats(&line,action + i + 1)) die_nomem(); + } + if (!stralloc_0(&line)) die_nomem(); + doit(line.s,msgnum,when,&bounce); + _exit(0); + } + + /* pre-VERP bounce, in QSBMF format */ + + substdio_fdbuf(&ssmsgin,read,0,msginbuf,sizeof(msginbuf)); + + flaghaveheader = 0; + flaghaveintro = 0; + + for (;;) { + if (!stralloc_copys(¶graph,"")) die_nomem(); + for (;;) { + if (getln(&ssmsgin,&line,&match,'\n') == -1) die_msgin(); + if (!match) die_trash(); + if (!stralloc_cat(¶graph,&line)) die_nomem(); + if (line.len <= 1) break; + } + + if (!flaghaveheader) { + if (!stralloc_copy(&header,¶graph)) die_nomem(); + flaghaveheader = 1; + continue; + } + + if (!flaghaveintro) { + if (paragraph.len < 15) die_trash(); + if (str_diffn(paragraph.s,"Hi. This is the",15)) die_trash(); + if (!stralloc_copy(&intro,¶graph)) die_nomem(); + flaghaveintro = 1; + continue; + } + + if (paragraph.s[0] == '-') + break; + + if (paragraph.s[0] == '<') { + if (!stralloc_copy(&failure,¶graph)) die_nomem(); + + if (!stralloc_copy(&bounce,&header)) die_nomem(); + if (!stralloc_cat(&bounce,&intro)) die_nomem(); + if (!stralloc_cat(&bounce,&failure)) die_nomem(); + + i = byte_chr(failure.s,failure.len,'\n'); + if (i < 3) die_trash(); + + if (!stralloc_copyb(&line,failure.s + 1,i - 3)) die_nomem(); + if (byte_chr(line.s,line.len,'\0') == line.len) { + if (!stralloc_0(&line)) die_nomem(); + doit(line.s,msgnum,when,&bounce); + } + } + } + + _exit(0); +} diff --git a/ezmlm-return=0 b/ezmlm-return=0 new file mode 100644 index 0000000..0eaa248 --- /dev/null +++ b/ezmlm-return=0 @@ -0,0 +1 @@ +ezmlm-return.1 diff --git a/ezmlm-return=x b/ezmlm-return=x new file mode 100644 index 0000000..7f99f7f --- /dev/null +++ b/ezmlm-return=x @@ -0,0 +1,23 @@ +quote.o +getconf.o +issub.o +subscribe.o +log.o +slurpclose.o +slurp.o +now.o +cookie.o +surf.a +lock.a +env.a +sig.a +strerr.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +fs.a +case.a +open.a diff --git a/ezmlm-send.1 b/ezmlm-send.1 new file mode 100644 index 0000000..ff70976 --- /dev/null +++ b/ezmlm-send.1 @@ -0,0 +1,86 @@ +.TH ezmlm-send 1 +.SH NAME +ezmlm-send \- distribute a message to a mailing list +.SH SYNOPSIS +.B ezmlm-send +.I dir +.SH DESCRIPTION +.B ezmlm-send +reads a mail message and +sends it to the mailing list stored in +.IR dir . +If +.I dir\fB/archived +exists, +.B ezmlm-send +records a copy of the message in the +.I dir\fB/archive +directory. + +At the beginning of the message, +.B ezmlm-send +prints a new +.B Mailing-List +field with the contents of +.IR dir\fB/mailinglist . +It rejects the message if there is already a +.B Mailing-List +field. + +.B ezmlm-send +then prints all the new fields listed in +.IR dir\fB/headeradd , +followed by an appropriate +.B Delivered-To +line. + +.B ezmlm-send +deletes any incoming fields with names listed in +.IR dir\fB/headerremove . + +.B ezmlm-send +does not distribute bounce messages: +if the environment variable +.B SENDER +is set, and is either empty or +.BR #@[] , +.B ezmlm-send +rejects the message. +.SH "SUBLISTS" +If +.I dir\fB/sublist +exists, +.B ezmlm-send +changes its behavior in several ways. + +First, if +.B SENDER +is set, +and the first line of +.I dir\fB/sublist +has the form +.IR parent\fB@\fIparenthost , +.B ezmlm-send +insists that +.B SENDER +have the form +.IR parent\fB...@\fIparenthost . + +Second, +.B ezmlm-send +demands that the message already have a +.B Mailing-List +field. + +Third, +.B ezmlm-send +does not add its own +.B Mailing-List +field. +.SH "SEE ALSO" +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm-reject(1), +ezmlm(5) diff --git a/ezmlm-send.c b/ezmlm-send.c new file mode 100644 index 0000000..5748891 --- /dev/null +++ b/ezmlm-send.c @@ -0,0 +1,319 @@ +#include "stralloc.h" +#include "subfd.h" +#include "strerr.h" +#include "error.h" +#include "qmail.h" +#include "env.h" +#include "lock.h" +#include "sig.h" +#include "open.h" +#include "getln.h" +#include "case.h" +#include "scan.h" +#include "str.h" +#include "fmt.h" +#include "readwrite.h" +#include "exit.h" +#include "substdio.h" +#include "getconf.h" +#include "constmap.h" + +#define FATAL "ezmlm-send: fatal: " + +void die_usage() +{ + strerr_die1x(100,"ezmlm-send: usage: ezmlm-send dir"); +} +void die_nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +char strnum[FMT_ULONG]; + +stralloc fnadir = {0}; +stralloc fnaf = {0}; +stralloc fnsub = {0}; +stralloc line = {0}; + +int flagarchived; +int fdarchive; +substdio ssarchive; +char archivebuf[1024]; + +int flagsublist; +stralloc sublist = {0}; +stralloc mailinglist = {0}; +stralloc outlocal = {0}; +stralloc outhost = {0}; +stralloc headerremove = {0}; +struct constmap headerremovemap; +stralloc headeradd = {0}; + +struct qmail qq; +substdio ssin; +char inbuf[1024]; +substdio ssout; +char outbuf[1]; + +int mywrite(fd,buf,len) +int fd; +char *buf; +unsigned int len; +{ + qmail_put(&qq,buf,len); + return len; +} + +void die_archive() +{ + strerr_die4sys(111,FATAL,"unable to write to ",fnaf.s,": "); +} +void die_numnew() +{ + strerr_die2sys(111,FATAL,"unable to create numnew: "); +} + +void put(buf,len) char *buf; int len; +{ + qmail_put(&qq,buf,len); + if (flagarchived) + if (substdio_put(&ssarchive,buf,len) == -1) die_archive(); +} + +void puts(buf) char *buf; +{ + qmail_puts(&qq,buf); + if (flagarchived) + if (substdio_puts(&ssarchive,buf) == -1) die_archive(); +} + +int sublistmatch(sender) +char *sender; +{ + int i; + int j; + + j = str_len(sender); + if (j < sublist.len) return 0; + + i = byte_rchr(sublist.s,sublist.len,'@'); + if (i == sublist.len) return 1; + + if (byte_diff(sublist.s,i,sender)) return 0; + if (case_diffb(sublist.s + i,sublist.len - i,sender + j - (sublist.len - i))) + return 0; + + return 1; +} + +substdio ssnumnew; +char numnewbuf[16]; +unsigned long msgnum; +stralloc num = {0}; + +char buf0[256]; +substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0)); + +void numwrite() +{ + int fd; + + fd = open_trunc("numnew"); + if (fd == -1) die_numnew(); + substdio_fdbuf(&ssnumnew,write,fd,numnewbuf,sizeof(numnewbuf)); + if (substdio_put(&ssnumnew,strnum,fmt_ulong(strnum,msgnum)) == -1) + die_numnew(); + if (substdio_puts(&ssnumnew,"\n") == -1) die_numnew(); + if (substdio_flush(&ssnumnew) == -1) die_numnew(); + if (fsync(fd) == -1) die_numnew(); + if (close(fd) == -1) die_numnew(); /* NFS stupidity */ + if (rename("numnew","num") == -1) + strerr_die2sys(111,FATAL,"unable to move numnew to num: "); +} + +stralloc mydtline = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + int fd; + char *dir; + int fdlock; + char *sender; + int flagmlwasthere; + int match; + int i; + char ch; + int flaginheader; + int flagbadfield; + + umask(022); + sig_pipeignore(); + + dir = argv[1]; + if (!dir) die_usage(); + + sender = env_get("SENDER"); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + fdlock = open_append("lock"); + if (fdlock == -1) + strerr_die4sys(111,FATAL,"unable to open ",dir,"/lock: "); + if (lock_ex(fdlock) == -1) + strerr_die4sys(111,FATAL,"unable to obtain ",dir,"/lock: "); + + if (qmail_open(&qq) == -1) + strerr_die2sys(111,FATAL,"unable to run qmail-queue: "); + + flagarchived = getconf_line(&line,"archived",0,FATAL,dir); + + getconf_line(&num,"num",1,FATAL,dir); + if (!stralloc_0(&num)) die_nomem(); + scan_ulong(num.s,&msgnum); + ++msgnum; + + getconf_line(&outhost,"outhost",1,FATAL,dir); + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + getconf_line(&mailinglist,"mailinglist",1,FATAL,dir); + flagsublist = getconf_line(&sublist,"sublist",0,FATAL,dir); + + getconf(&headerremove,"headerremove",1,FATAL,dir); + constmap_init(&headerremovemap,headerremove.s,headerremove.len,0); + + getconf(&headeradd,"headeradd",1,FATAL,dir); + for (i = 0;i < headeradd.len;++i) + if (!headeradd.s[i]) + headeradd.s[i] = '\n'; + + if (!stralloc_copys(&mydtline,"Delivered-To: mailing list ")) die_nomem(); + if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem(); + if (!stralloc_cats(&mydtline,"@")) die_nomem(); + if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem(); + if (!stralloc_cats(&mydtline,"\n")) die_nomem(); + + if (sender) { + if (!*sender) + strerr_die2x(100,FATAL,"I don't distribute bounce messages (#5.7.2)"); + if (str_equal(sender,"#@[]")) + strerr_die2x(100,FATAL,"I don't distribute bounce messages (#5.7.2)"); + if (flagsublist) + if (!sublistmatch(sender)) + strerr_die2x(100,FATAL,"this message is not from my parent list (#5.7.2)"); + } + + if (flagarchived) { + if (!stralloc_copys(&fnadir,"archive/")) die_nomem(); + if (!stralloc_catb(&fnadir,strnum,fmt_ulong(strnum,msgnum / 100))) die_nomem(); + if (!stralloc_copy(&fnaf,&fnadir)) die_nomem(); + if (!stralloc_cats(&fnaf,"/")) die_nomem(); + if (!stralloc_catb(&fnaf,strnum,fmt_uint0(strnum,(unsigned int) (msgnum % 100),2))) die_nomem(); + if (!stralloc_0(&fnadir)) die_nomem(); + if (!stralloc_0(&fnaf)) die_nomem(); + + if (mkdir(fnadir.s,0755) == -1) + if (errno != error_exist) + strerr_die4sys(111,FATAL,"unable to create ",fnadir.s,": "); + fdarchive = open_trunc(fnaf.s); + if (fdarchive == -1) + strerr_die4sys(111,FATAL,"unable to write ",fnaf.s,": "); + + substdio_fdbuf(&ssarchive,write,fdarchive,archivebuf,sizeof(archivebuf)); + } + + if (!flagsublist) { + puts("Mailing-List: "); + put(mailinglist.s,mailinglist.len); + puts("\n"); + } + put(headeradd.s,headeradd.len); + put(mydtline.s,mydtline.len); + + flagmlwasthere = 0; + flaginheader = 1; + flagbadfield = 0; + + for (;;) { + if (getln(&ss0,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + + if (flaginheader && match) { + if (line.len == 1) + flaginheader = 0; + if ((line.s[0] != ' ') && (line.s[0] != '\t')) { + flagbadfield = 0; + if (constmap(&headerremovemap,line.s,byte_chr(line.s,line.len,':'))) + flagbadfield = 1; + if (case_startb(line.s,line.len,"mailing-list:")) + flagmlwasthere = 1; + if (line.len == mydtline.len) + if (!byte_diff(line.s,line.len,mydtline.s)) + strerr_die2x(100,FATAL,"this message is looping: it already has my Delivered-To line (#5.4.6)"); + } + } + + if (!(flaginheader && flagbadfield)) + put(line.s,line.len); + + if (!match) + break; + } + + if (flagsublist) + if (!flagmlwasthere) + strerr_die2x(100,FATAL,"sublist messages must have Mailing-List (#5.7.2)"); + if (!flagsublist) + if (flagmlwasthere) + strerr_die2x(100,FATAL,"message already has Mailing-List (#5.7.2)"); + + if (flagarchived) { + if (substdio_flush(&ssarchive) == -1) die_archive(); + if (fsync(fdarchive) == -1) die_archive(); + if (fchmod(fdarchive,0744) == -1) die_archive(); + if (close(fdarchive) == -1) die_archive(); /* NFS stupidity */ + } + + numwrite(); + + if (!stralloc_copy(&line,&outlocal)) die_nomem(); + if (!stralloc_cats(&line,"-return-")) die_nomem(); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msgnum))) die_nomem(); + if (!stralloc_cats(&line,"-@")) die_nomem(); + if (!stralloc_cat(&line,&outhost)) die_nomem(); + if (!stralloc_cats(&line,"-@[]")) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + + qmail_from(&qq,line.s); + + for (i = 0;i < 53;++i) { + ch = 64 + i; + if (!stralloc_copys(&fnsub,"subscribers/")) die_nomem(); + if (!stralloc_catb(&fnsub,&ch,1)) strerr_die2x(111,FATAL,"out of memory"); + if (!stralloc_0(&fnsub)) strerr_die2x(111,FATAL,"out of memory"); + fd = open_read(fnsub.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,FATAL,"unable to read ",fnsub.s,": "); + } + else { + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + substdio_fdbuf(&ssout,mywrite,-1,outbuf,sizeof(outbuf)); + if (substdio_copy(&ssout,&ssin) != 0) + strerr_die4sys(111,FATAL,"unable to read ",fnsub.s,": "); + close(fd); + } + } + + switch(qmail_close(&qq)) { + case 0: + strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; + strerr_die2x(0,"ezmlm-send: info: qp ",strnum); + default: + --msgnum; + numwrite(); + strerr_die2x(111,FATAL,"temporary qmail-queue error"); + } +} diff --git a/ezmlm-send=0 b/ezmlm-send=0 new file mode 100644 index 0000000..40a6d36 --- /dev/null +++ b/ezmlm-send=0 @@ -0,0 +1 @@ +ezmlm-send.1 diff --git a/ezmlm-send=x b/ezmlm-send=x new file mode 100644 index 0000000..2ba0ed9 --- /dev/null +++ b/ezmlm-send=x @@ -0,0 +1,21 @@ +auto_qmail.o +getconf.o +qmail.o +constmap.o +slurp.o +slurpclose.o +wait.a +getln.a +strerr.a +sig.a +env.a +open.a +lock.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +fd.a +case.a +fs.a diff --git a/ezmlm-sub.1 b/ezmlm-sub.1 new file mode 100644 index 0000000..219b88f --- /dev/null +++ b/ezmlm-sub.1 @@ -0,0 +1,38 @@ +.TH ezmlm-sub 1 +.SH NAME +ezmlm-sub \- manually add addresses to a mailing list +.SH SYNOPSIS +.B ezmlm-sub +.I dir +[ +.I box\fB@\fIdomain ... +] +.SH DESCRIPTION +.B ezmlm-sub +adds each address +.I box\fB@\fIdomain +to the mailing list stored in +.IR dir . + +If +.I box\fB@\fIdomain +is already on the mailing list, +.B ezmlm-sub +leaves it there. + +.B ezmlm-sub +converts +.I domain +to lowercase before adding +.I box\fB@\fIdomain +to the mailing list. + +.I box\fB@\fIdomain +cannot be longer than 400 characters. +.SH "SEE ALSO" +ezmlm-list(1), +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-send(1), +ezmlm-unsub(1), +ezmlm(5) diff --git a/ezmlm-sub.c b/ezmlm-sub.c new file mode 100644 index 0000000..85fce6a --- /dev/null +++ b/ezmlm-sub.c @@ -0,0 +1,33 @@ +#include "strerr.h" +#include "subscribe.h" +#include "log.h" + +#define FATAL "ezmlm-sub: fatal: " +#define WARNING "ezmlm-sub: warning: " + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *addr; + + dir = argv[1]; + if (!dir) + strerr_die1x(100,"ezmlm-sub: usage: ezmlm-sub dir box@domain ..."); + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + argv += 2; + while (addr = *argv++) + switch(subscribe(addr,1)) { + case -1: + strerr_die1(111,FATAL,&subscribe_err); + case -2: + strerr_warn4(WARNING,"cannot subscribe ",addr,": ",&subscribe_err); + break; + case 1: + log("+manual",addr); + } + _exit(0); +} diff --git a/ezmlm-sub=0 b/ezmlm-sub=0 new file mode 100644 index 0000000..2d4630f --- /dev/null +++ b/ezmlm-sub=0 @@ -0,0 +1 @@ +ezmlm-sub.1 diff --git a/ezmlm-sub=x b/ezmlm-sub=x new file mode 100644 index 0000000..9218d9a --- /dev/null +++ b/ezmlm-sub=x @@ -0,0 +1,14 @@ +subscribe.o +log.o +now.o +fs.a +strerr.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +case.a +open.a +lock.a diff --git a/ezmlm-unsub.1 b/ezmlm-unsub.1 new file mode 100644 index 0000000..7223ae9 --- /dev/null +++ b/ezmlm-unsub.1 @@ -0,0 +1,35 @@ +.TH ezmlm-unsub 1 +.SH NAME +ezmlm-unsub \- manually remove addresses from a mailing list +.SH SYNOPSIS +.B ezmlm-unsub +.I dir +[ +.I box\fB@\fIdomain ... +] +.SH DESCRIPTION +.B ezmlm-unsub +removes each address +.I box\fB@\fIdomain +from the mailing list stored in +.IR dir . + +If +.I box\fB@\fIdomain +is not on the mailing list, +.B ezmlm-unsub +keeps it off. + +.B ezmlm-unsub +converts +.I domain +to lowercase before removing +.I box\fB@\fIdomain +from the mailing list. +.SH "SEE ALSO" +ezmlm-list(1), +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm(5) diff --git a/ezmlm-unsub.c b/ezmlm-unsub.c new file mode 100644 index 0000000..3f53890 --- /dev/null +++ b/ezmlm-unsub.c @@ -0,0 +1,34 @@ +#include "strerr.h" +#include "subscribe.h" +#include "log.h" + +#define FATAL "ezmlm-unsub: fatal: " +#define WARNING "ezmlm-unsub: warning: " + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *addr; + + dir = argv[1]; + if (!dir) + strerr_die1x(100,"ezmlm-unsub: usage: ezmlm-unsub dir box@domain ..."); + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + argv += 2; + while (addr = *argv++) + switch(subscribe(addr,0)) { + case -1: + strerr_die1(111,FATAL,&subscribe_err); + case -2: + strerr_warn4(WARNING,"cannot unsubscribe ",addr,": ",&subscribe_err); + break; + case 1: + log("-manual",addr); + } + + _exit(0); +} diff --git a/ezmlm-unsub=0 b/ezmlm-unsub=0 new file mode 100644 index 0000000..b651717 --- /dev/null +++ b/ezmlm-unsub=0 @@ -0,0 +1 @@ +ezmlm-unsub.1 diff --git a/ezmlm-unsub=x b/ezmlm-unsub=x new file mode 100644 index 0000000..9218d9a --- /dev/null +++ b/ezmlm-unsub=x @@ -0,0 +1,14 @@ +subscribe.o +log.o +now.o +fs.a +strerr.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +str.a +case.a +open.a +lock.a diff --git a/ezmlm-warn.1 b/ezmlm-warn.1 new file mode 100644 index 0000000..06fd0b0 --- /dev/null +++ b/ezmlm-warn.1 @@ -0,0 +1,39 @@ +.TH ezmlm-warn 1 +.SH NAME +ezmlm-warn \- send out bounce warnings +.SH SYNOPSIS +.B ezmlm-warn +.I dir +.SH DESCRIPTION +.B ezmlm-warn +sends out warning messages +for the mailing list stored in +.IR dir . + +.B ezmlm-warn +scans +.I dir\fB/bounce +for bounce messages received by +.BR ezmlm-return . +If it sees a distribution bounce for +.I box\fB@\fIdomain +received more than ten days ago, +it sends +.I box\fB@\fIdomain +a list of all the message numbers missed recently, +and deletes the bounce. +If it sees a warning bounce for +.I box\fB@\fIdomain +received more than ten days ago, +it sends +.I box\fB@\fIdomain +a probe, +and deletes the bounce. + +.B ezmlm-warn +will not send a warning or probe to an address that is +not currently a subscriber. +.SH "SEE ALSO" +ezmlm-make(1), +ezmlm-return(1), +ezmlm(5) diff --git a/ezmlm-warn.c b/ezmlm-warn.c new file mode 100644 index 0000000..3140976 --- /dev/null +++ b/ezmlm-warn.c @@ -0,0 +1,254 @@ +#include +#include +#include "direntry.h" +#include "readwrite.h" +#include "getln.h" +#include "substdio.h" +#include "stralloc.h" +#include "slurp.h" +#include "getconf.h" +#include "byte.h" +#include "error.h" +#include "str.h" +#include "strerr.h" +#include "sig.h" +#include "now.h" +#include "datetime.h" +#include "date822fmt.h" +#include "fmt.h" +#include "cookie.h" +#include "qmail.h" + +#define FATAL "ezmlm-warn: fatal: " +void die_usage() { strerr_die1x(100,"ezmlm-warn: usage: ezmlm-warn dir"); } +void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } + +stralloc key = {0}; +stralloc outhost = {0}; +stralloc outlocal = {0}; +stralloc mailinglist = {0}; + +unsigned long when; +char *dir; +stralloc fn = {0}; +struct stat st; + +void die_read() { strerr_die6sys(111,FATAL,"unable to read ",dir,"/",fn.s,": "); } + +char inbuf[1024]; +substdio ssin; +char textbuf[1024]; +substdio sstext; + +stralloc addr = {0}; +char strnum[FMT_ULONG]; +char hash[COOKIE]; +stralloc fnhash = {0}; +stralloc quoted = {0}; +stralloc line = {0}; + +struct qmail qq; +int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len; +{ + qmail_put(&qq,buf,len); + return len; +} +char qqbuf[1]; +substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf)); +struct datetime dt; +char date[DATE822FMT]; + +void copy(fn) +char *fn; +{ + int fd; + int match; + + fd = open_read(fn); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to open ",fn,": "); + + substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); + for (;;) { + if (getln(&sstext,&line,&match,'\n') == -1) + strerr_die4sys(111,FATAL,"unable to read ",fn,": "); + if (!match) + break; + qmail_put(&qq,line.s,line.len); + } + + close(fd); +} + +void doit(flagw) +int flagw; +{ + int i; + int fd; + int match; + int fdhash; + datetime_sec msgwhen; + + fd = open_read(fn.s); + if (fd == -1) die_read(); + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + + if (getln(&ssin,&addr,&match,'\0') == -1) die_read(); + if (!match) { close(fd); return; } + + if (!issub(addr.s)) { close(fd); /*XXX*/unlink(fn.s); return; } + + cookie(hash,"",0,"",addr.s,""); + if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem(); + if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem(); + if (!stralloc_0(&fnhash)) die_nomem(); + + if (qmail_open(&qq) == -1) + strerr_die2sys(111,FATAL,"unable to run qmail-queue: "); + + msgwhen = now(); + qmail_puts(&qq,"Mailing-List: "); + qmail_put(&qq,mailinglist.s,mailinglist.len); + qmail_puts(&qq,"\nDate: "); + datetime_tai(&dt,msgwhen); + qmail_put(&qq,date,date822fmt(date,&dt)); + qmail_puts(&qq,"Message-ID: <"); + qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) msgwhen)); + qmail_puts(&qq,"."); + qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) getpid())); + qmail_puts(&qq,".ezmlm-warn@"); + qmail_put(&qq,outhost.s,outhost.len); + qmail_puts(&qq,">\nFrom: "); + if (!quote("ed,&outlocal)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,"-help@"); + qmail_put(&qq,outhost.s,outhost.len); + qmail_puts(&qq,"\nTo: "); + if (!quote2("ed,addr.s)) die_nomem(); + qmail_put(&qq,quoted.s,quoted.len); + qmail_puts(&qq,flagw ? "\nSubject: ezmlm probe\n\n" : "\nSubject: ezmlm warning\n\n"); + + copy("text/top"); + copy(flagw ? "text/bounce-probe" : "text/bounce-warn"); + + if (!flagw) { + fdhash = open_read(fnhash.s); + if (fdhash == -1) { + if (errno != error_noent) + strerr_die6sys(111,FATAL,"unable to open ",dir,"/",fnhash.s,": "); + } + else { + copy("text/bounce-num"); + substdio_fdbuf(&sstext,read,fdhash,textbuf,sizeof(textbuf)); + if (substdio_copy(&ssqq,&sstext) < 0) + strerr_die6sys(111,FATAL,"unable to read ",dir,"/",fnhash.s,": "); + close(fdhash); + } + } + + copy("text/bounce-bottom"); + if (substdio_copy(&ssqq,&ssin) < 0) die_read(); + close(fd); + + strnum[fmt_ulong(strnum,when)] = 0; + cookie(hash,key.s,key.len,strnum,addr.s,flagw ? "P" : "W"); + if (!stralloc_copy(&line,&outlocal)) die_nomem(); + if (!stralloc_cats(&line,flagw ? "-return-probe-" : "-return-warn-")) die_nomem(); + if (!stralloc_cats(&line,strnum)) die_nomem(); + if (!stralloc_cats(&line,".")) die_nomem(); + if (!stralloc_catb(&line,hash,COOKIE)) die_nomem(); + if (!stralloc_cats(&line,"-")) die_nomem(); + i = str_chr(addr.s,'@'); + if (!stralloc_catb(&line,addr.s,i)) die_nomem(); + if (addr.s[i]) { + if (!stralloc_cats(&line,"=")) die_nomem(); + if (!stralloc_cats(&line,addr.s + i + 1)) die_nomem(); + } + if (!stralloc_cats(&line,"@")) die_nomem(); + if (!stralloc_cat(&line,&outhost)) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + qmail_from(&qq,line.s); + + qmail_to(&qq,addr.s); + if (qmail_close(&qq) != 0) + strerr_die2x(111,FATAL,"temporary qmail-queue error"); + + strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; + strerr_warn2("ezmlm-warn: info: qp ",strnum,0); + + if (!flagw) { + if (unlink(fnhash.s) == -1) + if (errno != error_noent) + strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fnhash.s,": "); + } + if (unlink(fn.s) == -1) + strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fn.s,": "); +} + +void main(argc,argv) +int argc; +char **argv; +{ + DIR *bouncedir; + direntry *d; + unsigned long bouncedate; + int fdlock; + + umask(022); + sig_pipeignore(); + when = (unsigned long) now(); + + dir = argv[1]; + if (!dir) die_usage(); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",dir,": "); + + switch(slurp("key",&key,32)) { + case -1: + strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: "); + case 0: + strerr_die3x(100,FATAL,dir,"/key does not exist"); + } + getconf_line(&outhost,"outhost",1,FATAL,dir); + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + getconf_line(&mailinglist,"mailinglist",1,FATAL,dir); + + fdlock = open_append("lockbounce"); + if (fdlock == -1) + strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: "); + if (lock_ex(fdlock) == -1) + strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: "); + + bouncedir = opendir("bounce"); + if (!bouncedir) + strerr_die4sys(111,FATAL,"unable to open ",dir,"/bounce: "); + + while (d = readdir(bouncedir)) { + if (str_equal(d->d_name,".")) continue; + if (str_equal(d->d_name,"..")) continue; + + if (!stralloc_copys(&fn,"bounce/")) die_nomem(); + if (!stralloc_cats(&fn,d->d_name)) die_nomem(); + if (!stralloc_0(&fn)) die_nomem(); + + if (stat(fn.s,&st) == -1) { + if (errno == error_noent) continue; + strerr_die6sys(111,FATAL,"unable to stat ",dir,"/",fn.s,": "); + } + + if (when > st.st_mtime + 3000000) + if (unlink(fn.s) == -1) + strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fn.s,": "); + + if ((d->d_name[0] == 'd') || (d->d_name[0] == 'w')) { + scan_ulong(d->d_name + 1,&bouncedate); + if (when > bouncedate + 1000000) + doit(d->d_name[0] == 'w'); + } + } + + closedir(bouncedir); + + _exit(0); +} diff --git a/ezmlm-warn=0 b/ezmlm-warn=0 new file mode 100644 index 0000000..e171750 --- /dev/null +++ b/ezmlm-warn=0 @@ -0,0 +1 @@ +ezmlm-warn.1 diff --git a/ezmlm-warn=x b/ezmlm-warn=x new file mode 100644 index 0000000..4425236 --- /dev/null +++ b/ezmlm-warn=x @@ -0,0 +1,26 @@ +auto_qmail.o +getconf.o +cookie.o +issub.o +now.o +slurpclose.o +slurp.o +quote.o +datetime.o +date822fmt.o +qmail.o +surf.a +case.a +strerr.a +sig.a +getln.a +substdio.a +stralloc.a +alloc.a +error.a +open.a +lock.a +str.a +fs.a +fd.a +wait.a diff --git a/ezmlm-weed.1 b/ezmlm-weed.1 new file mode 100644 index 0000000..5a5911f --- /dev/null +++ b/ezmlm-weed.1 @@ -0,0 +1,109 @@ +.TH ezmlm-weed 1 +.SH NAME +ezmlm-weed \- weed out useless messages +.SH SYNOPSIS +.B ezmlm-weed +.SH DESCRIPTION +.B ezmlm-weed +reads a mail message from its standard input. +If it recognizes the message as an MTA warning message or success message, +it exits 99; +this will cause +.B qmail-alias +to skip all further delivery instructions if +.B ezmlm-weed +is run from a +.B .qmail +file. +If the message seems innocent, +.B ezmlm-weed +exits 0. +.B ezmlm-weed +exits 111 if it runs out of memory. +.SH "RECOGNIZED FORMATS" +Generic success message, recommended for all MTAs: + +.EX + Subject: success notice +.EE + +Generic warning message, recommended for all MTAs: + +.EX + Subject: deferral notice +.EE + +Warning message from sendmail, MIME form: + +.EX + From: Mail Delivery Subsystem +.EE +.br +.EX + Subject: Warning +.EE +.br +.EX + Auto-Submitted: auto-generated (warning-timeout) +.EE +.br +.EX + This is a MIME-encapsulated message +.EE +.br +.EX + THIS IS A WARNING MESSAGE ONLY +.EE + +Non-MIME form: + +.EX + From: Mail Delivery Subsystem +.EE +.br +.EX + Subject: Warning +.EE +.br +.EX + Auto-Submitted: auto-generated (warning-timeout) +.EE +.br +.EX + THIS IS A WARNING MESSAGE ONLY +.EE + +Warning message from older version of sendmail: + +.EX + From: Mail Delivery Subsystem +.EE +.br +.EX + Subject: Returned mail: warning +.EE +.br +.EX + This is a MIME-encapsulated message +.EE +.br +.EX + THIS IS A WARNING MESSAGE ONLY +.EE + +Non-MIME form: + +.EX + From: Mail Delivery Subsystem +.EE +.br +.EX + Subject: Returned mail: warning +.EE +.br +.EX + THIS IS A WARNING MESSAGE ONLY +.EE +.SH "SEE ALSO" +ezmlm-return(1), +qmail-command(8) diff --git a/ezmlm-weed.c b/ezmlm-weed.c new file mode 100644 index 0000000..777fa03 --- /dev/null +++ b/ezmlm-weed.c @@ -0,0 +1,94 @@ +#include "stralloc.h" +#include "str.h" +#include "byte.h" +#include "readwrite.h" +#include "substdio.h" +#include "getln.h" +#include "strerr.h" + +char buf0[256]; +substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0)); + +#define FATAL "ezmlm-weed: fatal: " + +void get(sa) +stralloc *sa; +{ + int match; + if (getln(&ss0,sa,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + if (!match) _exit(0); +} + +stralloc line = {0}; +stralloc line1 = {0}; +stralloc line2 = {0}; +stralloc line3 = {0}; +stralloc line4 = {0}; +stralloc line5 = {0}; +stralloc line6 = {0}; +stralloc line7 = {0}; +stralloc line8 = {0}; + +char warn1[] = " **********************************************"; +char warn2[] = " ** THIS IS A WARNING MESSAGE ONLY **"; +char warn3[] = " ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **"; +char warn4[] = " **********************************************"; + +int flagmds = 0; +int flagsw = 0; +int flagsr = 0; +int flagas = 0; +int flagbw = 0; + +void main() +{ + int match; + + for (;;) { + get(&line); + if (line.len == 1) break; + + if (stralloc_starts(&line,"Subject: success notice")) + _exit(99); + if (stralloc_starts(&line,"Subject: deferral notice")) + _exit(99); + + if (stralloc_starts(&line,"From: Mail Delivery Subsystem + +int \fBfd_copy\fP(\fIto\fR,\fIfrom\fR); + +int \fIto\fR; +.br +int \fIfrom\fR; +.SH DESCRIPTION +.B fd_copy +copies +descriptor +.I from +to descriptor +.IR to . +If +.I to +was already open, +.B fd_copy +closes it. +.B fd_copy +always leaves +.I from +intact; +if +.I to +and +.I from +are the same number, +.B fd_copy +does nothing. + +.B fd_copy +returns 0 on success, -1 on error. +.B fd_copy +does not guarantee that +.I to +will remain open, if it was open, in case of error. +.SH "SEE ALSO" +dup(2), +fd_move(3) diff --git a/fd_copy.c b/fd_copy.c new file mode 100644 index 0000000..b9f7167 --- /dev/null +++ b/fd_copy.c @@ -0,0 +1,13 @@ +#include +#include "fd.h" + +int fd_copy(to,from) +int to; +int from; +{ + if (to == from) return 0; + if (fcntl(from,F_GETFL,0) == -1) return -1; + close(to); + if (fcntl(from,F_DUPFD,to) == -1) return -1; + return 0; +} diff --git a/fd_copy=0 b/fd_copy=0 new file mode 100644 index 0000000..f8a195e --- /dev/null +++ b/fd_copy=0 @@ -0,0 +1 @@ +fd_copy.3 diff --git a/fd_move.3 b/fd_move.3 new file mode 100644 index 0000000..94aa1b7 --- /dev/null +++ b/fd_move.3 @@ -0,0 +1,41 @@ +.TH fd_move 3 +.SH NAME +fd_move \- renumber a descriptor +.SH SYNTAX +.B #include + +int \fBfd_move\fP(\fIto\fR,\fIfrom\fR); + +int \fIto\fR; +.br +int \fIfrom\fR; +.SH DESCRIPTION +.B fd_move +moves +descriptor +.I from +to descriptor +.IR to . +If +.I to +was already open, +.B fd_move +closes it. +If the move is successful, +.B fd_move +closes +.IR from . +Exception: +if +.I to +and +.I from +are the same number, +.B fd_move +does nothing. + +.B fd_move +returns 0 on success, -1 on error. +.SH "SEE ALSO" +dup(2), +fd_copy(3) diff --git a/fd_move.c b/fd_move.c new file mode 100644 index 0000000..1aa557f --- /dev/null +++ b/fd_move.c @@ -0,0 +1,11 @@ +#include "fd.h" + +int fd_move(to,from) +int to; +int from; +{ + if (to == from) return 0; + if (fd_copy(to,from) == -1) return -1; + close(from); + return 0; +} diff --git a/fd_move=0 b/fd_move=0 new file mode 100644 index 0000000..c2c8185 --- /dev/null +++ b/fd_move=0 @@ -0,0 +1 @@ +fd_move.3 diff --git a/find-systype.sh b/find-systype.sh new file mode 100644 index 0000000..16266d3 --- /dev/null +++ b/find-systype.sh @@ -0,0 +1,144 @@ +# oper-:arch-:syst-:chip-:kern- +# oper = operating system type; e.g., sunos-4.1.4 +# arch = machine language; e.g., sparc +# syst = which binaries can run; e.g., sun4 +# chip = chip model; e.g., micro-2-80 +# kern = kernel version; e.g., sun4m +# dependence: arch --- chip +# \ \ +# oper --- syst --- kern +# so, for example, syst is interpreted in light of oper, but chip is not. +# anyway, no slashes, no extra colons, no uppercase letters. +# the point of the extra -'s is to ease parsing: can add hierarchies later. +# e.g., *:i386-*:*:pentium-*:* would handle pentium-100 as well as pentium, +# and i386-486 (486s do have more instructions, you know) as well as i386. +# the idea here is to include ALL useful available information. + +exec 2>/dev/null +sys="`uname -s | tr '/:[A-Z]' '..[a-z]'`" +if [ x"$sys" != x ] +then + unamer="`uname -r | tr /: ..`" + unamem="`uname -m | tr /: ..`" + unamev="`uname -v | tr /: ..`" + + case "$sys" in + bsd.os) + # in bsd 4.4, uname -v does not have useful info. + # in bsd 4.4, uname -m is arch, not chip. + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" + kern="" + ;; + freebsd) + # see above about bsd 4.4 + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" # hopefully + kern="" + ;; + netbsd) + # see above about bsd 4.4 + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" # hopefully + kern="" + ;; + linux) + # as in bsd 4.4, uname -v does not have useful info. + oper="$sys-$unamer" + syst="" + chip="$unamem" + kern="" + case "$chip" in + i386|i486|i586|i686) + arch="i386" + ;; + alpha) + arch="alpha" + ;; + esac + ;; + aix) + # naturally IBM has to get uname -r and uname -v backwards. dorks. + oper="$sys-$unamev-$unamer" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + sunos) + oper="$sys-$unamer-$unamev" + arch="`(uname -p || mach) | tr /: ..`" + syst="`arch | tr /: ..`" + chip="$unamem" # this is wrong; is there any way to get the real info? + kern="`arch -k | tr /: ..`" + ;; + unix_sv) + oper="$sys-$unamer-$unamev" + arch="`uname -m`" + syst="" + chip="$unamem" + kern="" + ;; + *) + oper="$sys-$unamer-$unamev" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + esac +else + $CC -c trycpp.c + $LD -o trycpp trycpp.o + case `./trycpp` in + nextstep) + oper="nextstep-`hostinfo | sed -n 's/^[ ]*NeXT Mach \([^:]*\):.*$/\1/p'`" + arch="`hostinfo | sed -n 's/^Processor type: \(.*\) (.*)$/\1/p' | tr /: ..`" + syst="" + chip="`hostinfo | sed -n 's/^Processor type: .* (\(.*\))$/\1/p' | tr ' /:' '...'`" + kern="" + ;; + *) + oper="unknown" + arch="" + syst="" + chip="" + kern="" + ;; + esac + rm -f trycpp.o trycpp +fi + +case "$chip" in +80486) + # let's try to be consistent here. (BSD/OS) + chip=i486 + ;; +i486DX) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx + ;; +i486.DX2) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx2 + ;; +Intel.586) + # no, you nitwits, there is no such chip. (NeXTStep) + chip=pentium + ;; +i586) + # no, you nitwits, there is no such chip. (Linux) + chip=pentium + ;; +i686) + # STOP SAYING THAT! (Linux) + chip=ppro +esac + +echo "$oper-:$arch-:$syst-:$chip-:$kern-" | tr ' [A-Z]' '.[a-z]' diff --git a/fmt.h b/fmt.h new file mode 100644 index 0000000..ba2fe16 --- /dev/null +++ b/fmt.h @@ -0,0 +1,25 @@ +#ifndef FMT_H +#define FMT_H + +#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */ +#define FMT_LEN ((char *) 0) /* convenient abbreviation */ + +extern unsigned int fmt_uint(); +extern unsigned int fmt_uint0(); +extern unsigned int fmt_xint(); +extern unsigned int fmt_nbbint(); +extern unsigned int fmt_ushort(); +extern unsigned int fmt_xshort(); +extern unsigned int fmt_nbbshort(); +extern unsigned int fmt_ulong(); +extern unsigned int fmt_xlong(); +extern unsigned int fmt_nbblong(); + +extern unsigned int fmt_plusminus(); +extern unsigned int fmt_minus(); +extern unsigned int fmt_0x(); + +extern unsigned int fmt_str(); +extern unsigned int fmt_strn(); + +#endif diff --git a/fmt_str.c b/fmt_str.c new file mode 100644 index 0000000..48930cf --- /dev/null +++ b/fmt_str.c @@ -0,0 +1,12 @@ +#include "fmt.h" + +unsigned int fmt_str(s,t) +register char *s; register char *t; +{ + register unsigned int len; + char ch; + len = 0; + if (s) { while (ch = t[len]) s[len++] = ch; } + else while (t[len]) len++; + return len; +} diff --git a/fmt_uint.c b/fmt_uint.c new file mode 100644 index 0000000..8595be8 --- /dev/null +++ b/fmt_uint.c @@ -0,0 +1,6 @@ +#include "fmt.h" + +unsigned int fmt_uint(s,u) register char *s; register unsigned int u; +{ + register unsigned long l; l = u; return fmt_ulong(s,l); +} diff --git a/fmt_uint0.c b/fmt_uint0.c new file mode 100644 index 0000000..81705f6 --- /dev/null +++ b/fmt_uint0.c @@ -0,0 +1,10 @@ +#include "fmt.h" + +unsigned int fmt_uint0(s,u,n) char *s; unsigned int u; unsigned int n; +{ + unsigned int len; + len = fmt_uint(FMT_LEN,u); + while (len < n) { if (s) *s++ = '0'; ++len; } + if (s) fmt_uint(s,u); + return len; +} diff --git a/fmt_ulong.c b/fmt_ulong.c new file mode 100644 index 0000000..ab12e8c --- /dev/null +++ b/fmt_ulong.c @@ -0,0 +1,13 @@ +#include "fmt.h" + +unsigned int fmt_ulong(s,u) register char *s; register unsigned long u; +{ + register unsigned int len; register unsigned long q; + len = 1; q = u; + while (q > 9) { ++len; q /= 10; } + if (s) { + s += len; + do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */ + } + return len; +} diff --git a/fork.h.do b/fork.h.do new file mode 100644 index 0000000..e095298 --- /dev/null +++ b/fork.h.do @@ -0,0 +1,7 @@ +dependon compile load tryvfork.c fork.h1 fork.h2 +( ./compile tryvfork.c && ./load tryvfork ) >/dev/null 2>&1 \ +&& cat fork.h2 || cat fork.h1 +rm -f tryvfork.o tryvfork +formake '( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null 2>&1 \' +formake '&& cat fork.h2 || cat fork.h1 ) > fork.h' +formake 'rm -f tryvfork.o tryvfork' diff --git a/fork.h1 b/fork.h1 new file mode 100644 index 0000000..b786255 --- /dev/null +++ b/fork.h1 @@ -0,0 +1,7 @@ +#ifndef FORK_H +#define FORK_H + +extern int fork(); +#define vfork fork + +#endif diff --git a/fork.h2 b/fork.h2 new file mode 100644 index 0000000..41773b6 --- /dev/null +++ b/fork.h2 @@ -0,0 +1,7 @@ +#ifndef FORK_H +#define FORK_H + +extern int fork(); +extern int vfork(); + +#endif diff --git a/fs=l b/fs=l new file mode 100644 index 0000000..9e09636 --- /dev/null +++ b/fs=l @@ -0,0 +1,6 @@ +fmt_str.o +fmt_uint.o +fmt_uint0.o +fmt_ulong.o +scan_ulong.o +scan_8long.o diff --git a/gen_alloc.h b/gen_alloc.h new file mode 100644 index 0000000..b94a956 --- /dev/null +++ b/gen_alloc.h @@ -0,0 +1,7 @@ +#ifndef GEN_ALLOC_H +#define GEN_ALLOC_H + +#define GEN_ALLOC_typedef(ta,type,field,len,a) \ + typedef struct ta { type *field; unsigned int len; unsigned int a; } ta; + +#endif diff --git a/gen_allocdefs.h b/gen_allocdefs.h new file mode 100644 index 0000000..783a9b1 --- /dev/null +++ b/gen_allocdefs.h @@ -0,0 +1,34 @@ +#ifndef GEN_ALLOC_DEFS_H +#define GEN_ALLOC_DEFS_H + +#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \ +int ta_ready(x,n) register ta *x; register unsigned int n; \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \ +int ta_rplus(x,n) register ta *x; register unsigned int n; \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; n += x->len; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \ +int ta_append(x,i) register ta *x; register type *i; \ +{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; } + +#endif diff --git a/getconf.c b/getconf.c new file mode 100644 index 0000000..89b6d31 --- /dev/null +++ b/getconf.c @@ -0,0 +1,61 @@ +#include "stralloc.h" +#include "slurp.h" +#include "strerr.h" +#include "getconf.h" + +static stralloc data = {0}; + +void nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,"out of memory"); +} + +int getconf(sa,fn,flagrequired,fatal,dir) +stralloc *sa; +char *fatal; +int flagrequired; +char *dir; +char *fn; +{ + int i; + int j; + int k; + + if (!stralloc_copys(&data,"")) + nomem(fatal); + switch(slurp(fn,&data,128)) { + case -1: + strerr_die6sys(111,fatal,"unable to read ",dir,"/",fn,": "); + case 0: + if (!flagrequired) + return 0; + strerr_die5x(100,fatal,dir,"/",fn," does not exist"); + } + if (!stralloc_append(&data,"\n")) nomem(fatal); + if (!stralloc_copys(sa,"")) nomem(fatal); + i = 0; + for (j = 0;j < data.len;++j) + if (data.s[j] == '\n') { + k = j; + while ((k > i) && ((data.s[k-1] == ' ') || (data.s[k-1] == '\t'))) --k; + if ((k > i) && (data.s[i] != '#')) { + if (!stralloc_catb(sa,data.s + i,k - i)) nomem(fatal); + if (!stralloc_0(sa)) nomem(fatal); + } + i = j + 1; + } + return 1; +} + +int getconf_line(sa,fn,flagrequired,fatal,dir) +stralloc *sa; +char *fatal; +int flagrequired; +char *dir; +char *fn; +{ + if (!getconf(sa,fn,flagrequired,fatal,dir)) return 0; + sa->len = byte_chr(sa->s,sa->len,0); + return 1; +} diff --git a/getconf.h b/getconf.h new file mode 100644 index 0000000..20962f0 --- /dev/null +++ b/getconf.h @@ -0,0 +1,7 @@ +#ifndef GETCONF_H +#define GETCONF_H + +extern int getconf(); +extern int getconf_line(); + +#endif diff --git a/getln.3 b/getln.3 new file mode 100644 index 0000000..ffe1953 --- /dev/null +++ b/getln.3 @@ -0,0 +1,51 @@ +.TH getln 3 +.SH NAME +getln \- read one line of data +.SH SYNTAX +.B #include + +int \fBgetln\fP(&\fIss\fR,&\fIsa\fR,&\fImatch\fR,\fIsep\fR); + +substdio \fIss\fR; +.br +stralloc \fIsa\fR; +.br +int \fImatch\fR; +.br +int \fIsep\fR; +.SH DESCRIPTION +.B getln +reads a line of characters, terminated by a +.I sep +character, +from +.IR ss . +It returns the line in +.I sa +and sets +.I match +to 1. + +If +.B getln +sees end-of-input before it sees +.IR sep , +it returns the partial line in +.I sa +and sets +.I match +to 0. + +.B getln +normally returns 0. +If it runs out of memory, +or encounters an error from +.IR ss , +it returns -1, +setting +.B errno +appropriately. +.SH "SEE ALSO" +stralloc(3), +substdio(3), +getln2(3) diff --git a/getln.c b/getln.c new file mode 100644 index 0000000..c5cb097 --- /dev/null +++ b/getln.c @@ -0,0 +1,20 @@ +#include "substdio.h" +#include "byte.h" +#include "stralloc.h" +#include "getln.h" + +int getln(ss,sa,match,sep) +register substdio *ss; +register stralloc *sa; +int *match; +int sep; +{ + char *cont; + unsigned int clen; + + if (getln2(ss,sa,&cont,&clen,sep) == -1) return -1; + if (!clen) { *match = 0; return 0; } + if (!stralloc_catb(sa,cont,clen)) return -1; + *match = 1; + return 0; +} diff --git a/getln.h b/getln.h new file mode 100644 index 0000000..cf4f934 --- /dev/null +++ b/getln.h @@ -0,0 +1,7 @@ +#ifndef GETLN_H +#define GETLN_H + +extern int getln(); +extern int getln2(); + +#endif diff --git a/getln2.3 b/getln2.3 new file mode 100644 index 0000000..f95105a --- /dev/null +++ b/getln2.3 @@ -0,0 +1,64 @@ +.TH getln2 3 +.SH NAME +getln2 \- read one line of data +.SH SYNTAX +.B #include + +int \fBgetln2\fP(&\fIss\fR,&\fIsa\fR,&\fIcont\fR,&\fIclen\fR,\fIsep\fR); + +substdio \fIss\fR; +.br +stralloc \fIsa\fR; +.br +char *\fIcont\fR; +.br +unsigned int \fIclen\fR; +.br +int \fIsep\fR; +.SH DESCRIPTION +.B getln2 +reads a line of characters, terminated by a +.I sep +character, +from +.IR ss . + +The line is returned in two pieces. +The first piece is stored in +.IR sa . +The second piece is +.IR cont , +a pointer to +.I clen +characters inside the +.I ss +buffer. +The second piece must be copied somewhere else +before +.I ss +is used again. + +If +.B getln2 +sees end-of-input before it sees +.IR sep , +it sets +.I clen +to 0 and does not set +.IR cont . +It puts the partial line into +.IR sa . + +.B getln2 +normally returns 0. +If it runs out of memory, +or encounters an error from +.IR ss , +it returns -1, +setting +.B errno +appropriately. +.SH "SEE ALSO" +stralloc(3), +substdio(3), +getln(3) diff --git a/getln2.c b/getln2.c new file mode 100644 index 0000000..9e576e9 --- /dev/null +++ b/getln2.c @@ -0,0 +1,31 @@ +#include "substdio.h" +#include "stralloc.h" +#include "byte.h" +#include "getln.h" + +int getln2(ss,sa,cont,clen,sep) +register substdio *ss; +register stralloc *sa; +/*@out@*/char **cont; +/*@out@*/unsigned int *clen; +int sep; +{ + register char *x; + register unsigned int i; + int n; + + if (!stralloc_ready(sa,0)) return -1; + sa->len = 0; + + for (;;) { + n = substdio_feed(ss); + if (n < 0) return -1; + if (n == 0) { *clen = 0; return 0; } + x = substdio_PEEK(ss); + i = byte_chr(x,n,sep); + if (i < n) { substdio_SEEK(ss,*clen = i + 1); *cont = x; return 0; } + if (!stralloc_readyplus(sa,n)) return -1; + i = sa->len; + sa->len = i + substdio_get(ss,sa->s + i,n); + } +} diff --git a/getln2=0 b/getln2=0 new file mode 100644 index 0000000..ee6879c --- /dev/null +++ b/getln2=0 @@ -0,0 +1 @@ +getln2.3 diff --git a/getln=0 b/getln=0 new file mode 100644 index 0000000..68df95c --- /dev/null +++ b/getln=0 @@ -0,0 +1 @@ +getln.3 diff --git a/getln=l b/getln=l new file mode 100644 index 0000000..b0f37fa --- /dev/null +++ b/getln=l @@ -0,0 +1,2 @@ +getln.o +getln2.o diff --git a/getopt.3 b/getopt.3 new file mode 100644 index 0000000..ecbf50a --- /dev/null +++ b/getopt.3 @@ -0,0 +1,235 @@ +.TH getopt 3 +.SH NAME +getopt \- get option character from command line +.SH SYNTAX +.B #include + +char *\fBoptarg\fP; +.br +int \fBoptind\fP; +.br +int \fBoptpos\fP; +.br +int \fBopteof\fP; +.br +int \fBoptproblem\fP; +.br +char *\fBoptprogname\fP; +.br +int \fBopterr\fP; + +int \fBgetopt(\fP\fIargc,argv,opts\fR\fB)\fP; + +int \fIargc\fR; +.br +char **\fIargv\fR; +.br +char *\fIopts\fR; +.SH DESCRIPTION +This is a clone version of +the standard +.B getopt +library, +built on top of +.BR subgetopt(3) . + +See +.B subgetopt(3) +for a detailed description of +.B getopt +processing. +The main difference between +.B getopt +and +.B subgetopt +is that +.B getopt +prints error messages +in case of problems. +To turn off these error messages, set +.B opterr +(default nonzero) +to zero. + +This clone version of +.B getopt +also provides an +.B optprogname +variable. +There are two uses for this variable: + +(1) +By default +.B optprogname +is null. +When +.B getopt +sees this, +it +attempts to initialize +.B optprogname +from +.IR argv\fB[0] , +stripping the directory name. +The calling program can use +.B optprogname +after calling +.B getopt +at least once. +This is appropriate if the name of the program should be +determined from its command line. + +(2) +.B getopt +prints +.B optprogname +at the beginning +of any error messages. +So the calling program can, +before calling +.BR getopt , +initialize +.B optprogname +as desired. +This is appropriate if the name of the program should not be +determined from its command line. +.SH "COMPATIBILITY" +Old versions of +.B getopt +do not include +.BR opterr . +.BR optpos , +.BR opteof , +.BR optproblem , +and +.B optprogname +are specific to this clone version of +.BR getopt . + +Many features of this clone version of +.B getopt +are poorly defined, if available at all, +in most versions of +.BR getopt . +For example, the standard +.B getopt +interface does not define +.B optind +until the end of the option list. +And +.B optarg +is not defined +unless +.B getopt +has just returned +an option which takes an argument. +In this clone version, +.B optind +and +.B optpos +always indicate the next character to be read, +and +.B optarg +is null whenever +the current option does not take an argument. +See +.B subgetopt(3) +for precise definitions of the parsing procedure. + +When it reaches the end of the option list, +this version of +.B getopt +always returns +.BR opteof , +which is the same as +.BR subgetoptdone , +which is initialized to +.BR SUBGETOPTDONE , +which is defined as \-1. +The standard behavior is to return +EOF +from +.B stdio(3). +This is incompatible +on any weird machine where +EOF is different from \-1. +The calling program could set +.B opteof +to EOF to imitate the standard behavior. + +Like most versions of +.BR getopt , +this clone version allows, but does not demand, that +option arguments be +separated from the option by whitespace, i.e., be +in the next command-line argument. + +Some versions of +.B getopt +provide an +.B optopt +variable. +.B optopt +is incompatible across systems: +for example, +GNU +.B getopt +uses it the same way that this clone version uses +.BR optproblem , +while +BSD +.B getopt +uses it to +indicate the last option character returned by +.BR getopt . +This clone version does not provide +.BR optopt . +The use of +.B optopt +is strongly discouraged. + +Some versions of +.B getopt +do not recognize a double hyphen as the end of arguments. +This version allows a double hyphen, or in fact any argument beginning +with two hyphens. + +A lone hyphen is always recognized as the end of arguments. +Some versions of +.B getopt +allow lone hyphens as options. +This practice is wrong and is strongly discouraged. +.SH "SYNTAX NOTE" +.B getopt +is actually a macro abbreviation for +.BR getoptmine . +The external +.B opterr +and +.B optprogname +variables +are macros for +.B getopterr +and +.BR getoptprogname . +All the other +.B opt +variables are macros +for +.BR subgetopt . +These macros are defined in +.BR , +unless +.B GETOPTNOSHORT +is defined. +Further macros are defined in +.BR , +which is included by +.BR , +unless +.B SUBGETOPTNOSHORT +is defined. +.SH VERSION +getopt version 1.9, 931129. +.SH AUTHOR +Placed into the public domain by Daniel J. Bernstein. diff --git a/getopt=0 b/getopt=0 new file mode 100644 index 0000000..52e530c --- /dev/null +++ b/getopt=0 @@ -0,0 +1 @@ +getopt.3 diff --git a/getopt=l b/getopt=l new file mode 100644 index 0000000..a667e1e --- /dev/null +++ b/getopt=l @@ -0,0 +1,2 @@ +subgetopt.o +sgetopt.o diff --git a/hasflock.h.do b/hasflock.h.do new file mode 100644 index 0000000..c7d8678 --- /dev/null +++ b/hasflock.h.do @@ -0,0 +1,7 @@ +dependon tryflock.c compile load +( ./compile tryflock.c && ./load tryflock ) >/dev/null 2>&1 \ +&& echo \#define HASFLOCK 1 +rm -f tryflock.o tryflock +formake '( ( ./compile tryflock.c && ./load tryflock ) >/dev/null 2>&1 \' +formake '&& echo \#define HASFLOCK 1 || exit 0 ) > hasflock.h' +formake 'rm -f tryflock.o tryflock' diff --git a/hassgact.h.do b/hassgact.h.do new file mode 100644 index 0000000..df277d5 --- /dev/null +++ b/hassgact.h.do @@ -0,0 +1,7 @@ +dependon trysgact.c compile load +( ./compile trysgact.c && ./load trysgact ) >/dev/null 2>&1 \ +&& echo \#define HASSIGACTION 1 +rm -f trysgact.o trysgact +formake '( ( ./compile trysgact.c && ./load trysgact ) >/dev/null 2>&1 \' +formake '&& echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h' +formake 'rm -f trysgact.o trysgact' diff --git a/install.c b/install.c new file mode 100644 index 0000000..24f0916 --- /dev/null +++ b/install.c @@ -0,0 +1,140 @@ +#include "substdio.h" +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "exit.h" +#include "open.h" +#include "error.h" +#include "strerr.h" +#include "byte.h" + +stralloc target = {0}; +char *to; + +#define FATAL "install: fatal: " +void nomem() { strerr_die2x(111,FATAL,"out of memory"); } + +char inbuf[SUBSTDIO_INSIZE]; +char outbuf[SUBSTDIO_OUTSIZE]; +substdio ssin; +substdio ssout; + +void doit(line) +stralloc *line; +{ + char *x; + unsigned int xlen; + unsigned int i; + char *type; + char *uidstr; + char *gidstr; + char *modestr; + char *mid; + char *name; + unsigned long uid; + unsigned long gid; + unsigned long mode; + int fdin; + int fdout; + + x = line->s; xlen = line->len; + + type = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + uidstr = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + gidstr = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + modestr = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + mid = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + name = x; + i = byte_chr(x,xlen,':'); if (i == xlen) return; + x[i++] = 0; x += i; xlen -= i; + + if (!stralloc_copys(&target,to)) nomem(); + if (!stralloc_cats(&target,mid)) nomem(); + if (!stralloc_cats(&target,name)) nomem(); + if (!stralloc_0(&target)) nomem(); + + uid = -1; if (*uidstr) scan_ulong(uidstr,&uid); + gid = -1; if (*gidstr) scan_ulong(gidstr,&gid); + scan_8long(modestr,&mode); + + switch(*type) { + case 'd': + if (mkdir(target.s,0700) == -1) + if (errno != error_exist) + strerr_die4sys(111,FATAL,"unable to mkdir ",target.s,": "); + break; + + case 'c': + fdin = open_read(name); + if (fdin == -1) + strerr_die4sys(111,FATAL,"unable to read ",name,": "); + substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf)); + + fdout = open_trunc(target.s); + if (fdout == -1) + strerr_die4sys(111,FATAL,"unable to write ",target.s,": "); + substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf)); + + switch(substdio_copy(&ssout,&ssin)) { + case -2: + strerr_die4sys(111,FATAL,"unable to read ",name,": "); + case -3: + strerr_die4sys(111,FATAL,"unable to write ",target.s,": "); + } + + close(fdin); + if (substdio_flush(&ssout) == -1) + strerr_die4sys(111,FATAL,"unable to write ",target.s,": "); + if (fsync(fdout) == -1) + strerr_die4sys(111,FATAL,"unable to write ",target.s,": "); + close(fdout); + break; + + default: + return; + } + + if (chown(target.s,uid,gid) == -1) + strerr_die4sys(111,FATAL,"unable to chown ",target.s,": "); + if (chmod(target.s,mode) == -1) + strerr_die4sys(111,FATAL,"unable to chmod ",target.s,": "); +} + +char buf[256]; +substdio in = SUBSTDIO_FDBUF(read,0,buf,sizeof(buf)); +stralloc line = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + int match; + + umask(077); + + to = argv[1]; + if (!to) strerr_die2x(100,FATAL,"install: usage: install dir"); + + for (;;) { + if (getln(&in,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + doit(&line); + if (!match) + _exit(0); + } +} diff --git a/install=x b/install=x new file mode 100644 index 0000000..6dc960b --- /dev/null +++ b/install=x @@ -0,0 +1,9 @@ +getln.a +strerr.a +substdio.a +stralloc.a +alloc.a +open.a +error.a +str.a +fs.a diff --git a/issub.c b/issub.c new file mode 100644 index 0000000..81ab6ad --- /dev/null +++ b/issub.c @@ -0,0 +1,87 @@ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "lock.h" +#include "error.h" +#include "issub.h" +#include "uint32.h" + +static stralloc addr = {0}; +static stralloc line = {0}; +static stralloc fn = {0}; +static int fd; +static substdio ss; +static char ssbuf[256]; + +static int doit(userhost) +char *userhost; +{ + int j; + uint32 h; + char ch; + int match; + + if (!stralloc_copys(&addr,"T")) return -2; + if (!stralloc_cats(&addr,userhost)) return -2; + + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) return 0; + case_lowerb(addr.s + j + 1,addr.len - j - 1); + + h = 5381; + for (j = 0;j < addr.len;++j) + h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; + ch = 64 + (h % 53); + + if (!stralloc_0(&addr)) return -2; + + if (!stralloc_copys(&fn,"subscribers/")) return -2; + if (!stralloc_catb(&fn,&ch,1)) return -2; + if (!stralloc_0(&fn)) return -2; + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) return -3; + return 0; + } + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) { close(fd); return -3; } + if (!match) break; + if (line.len == addr.len) + if (!byte_diff(line.s,line.len,addr.s)) { close(fd); return 1; } + } + + close(fd); + return 0; +} + +struct strerr issub_err; + +int issub(userhost) +char *userhost; +{ + int fdlock; + int r; + + fdlock = open_append("lock"); + if (fdlock == -1) + STRERR_SYS(-1,issub_err,"unable to open lock: ") + if (lock_ex(fdlock) == -1) { + close(fdlock); + STRERR_SYS(-1,issub_err,"unable to obtain lock: ") + } + + r = doit(userhost); + close(fdlock); + + if (r == -2) STRERR(-1,issub_err,"out of memory") + if (r == -3) STRERR_SYS3(-1,issub_err,"unable to read ",fn.s,": ") + + return r; +} diff --git a/issub.h b/issub.h new file mode 100644 index 0000000..71fb379 --- /dev/null +++ b/issub.h @@ -0,0 +1,10 @@ +#ifndef ISSUB_H +#define ISSUB_H + +#include "strerr.h" + +extern struct strerr issub_err; + +extern int issub(); + +#endif diff --git a/it.do b/it.do new file mode 100644 index 0000000..667603f --- /dev/null +++ b/it.do @@ -0,0 +1,4 @@ +dependon \ +ezmlm-make ezmlm-manage ezmlm-send ezmlm-reject \ +ezmlm-return ezmlm-warn ezmlm-weed \ +ezmlm-list ezmlm-sub ezmlm-unsub diff --git a/lock.h b/lock.h new file mode 100644 index 0000000..a7dee41 --- /dev/null +++ b/lock.h @@ -0,0 +1,8 @@ +#ifndef LOCK_H +#define LOCK_H + +extern int lock_ex(); +extern int lock_un(); +extern int lock_exnb(); + +#endif diff --git a/lock=l b/lock=l new file mode 100644 index 0000000..9927cef --- /dev/null +++ b/lock=l @@ -0,0 +1 @@ +lock_ex.o diff --git a/lock_ex.c b/lock_ex.c new file mode 100644 index 0000000..a3351c9 --- /dev/null +++ b/lock_ex.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include "hasflock.h" +#include "lock.h" + +#ifdef HASFLOCK +int lock_ex(fd) int fd; { return flock(fd,LOCK_EX); } +#else +int lock_ex(fd) int fd; { return lockf(fd,1,0); } +#endif diff --git a/log.c b/log.c new file mode 100644 index 0000000..15e732e --- /dev/null +++ b/log.c @@ -0,0 +1,37 @@ +#include "substdio.h" +#include "readwrite.h" +#include "stralloc.h" +#include "log.h" +#include "now.h" +#include "fmt.h" +#include "open.h" + +static substdio ss; +static char buf[1]; +static char num[FMT_ULONG]; +static stralloc line = {0}; + +void log(event,addr) +char *event; +char *addr; +{ + char ch; + int fd; + + if (!stralloc_copyb(&line,num,fmt_ulong(num,(unsigned long) now()))) return; + if (!stralloc_cats(&line," ")) return; + if (!stralloc_cats(&line,event)) return; + if (!stralloc_cats(&line," ")) return; + while (ch = *addr++) { + if ((ch < 33) || (ch > 126)) ch = '?'; + if (!stralloc_append(&line,&ch)) return; + } + if (!stralloc_cats(&line,"\n")) return; + + fd = open_append("Log"); + if (fd == -1) return; + substdio_fdbuf(&ss,write,fd,buf,sizeof(buf)); + substdio_putflush(&ss,line.s,line.len); + close(fd); + return; +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..d973be9 --- /dev/null +++ b/log.h @@ -0,0 +1,6 @@ +#ifndef LOG_H +#define LOG_H + +extern void log(); + +#endif diff --git a/make-compile.sh b/make-compile.sh new file mode 100644 index 0000000..a1eb501 --- /dev/null +++ b/make-compile.sh @@ -0,0 +1 @@ +echo exec "$CC" -c '${1+"$@"}' diff --git a/make-load.sh b/make-load.sh new file mode 100644 index 0000000..de07d2e --- /dev/null +++ b/make-load.sh @@ -0,0 +1,2 @@ +echo 'main="$1"; shift' +echo exec "$LD" '-o "$main" "$main".o ${1+"$@"}' diff --git a/make-makelib.sh b/make-makelib.sh new file mode 100644 index 0000000..d6b7c8c --- /dev/null +++ b/make-makelib.sh @@ -0,0 +1,16 @@ +echo 'main="$1"; shift' +echo 'rm -f "$main"' +echo 'ar cr "$main" ${1+"$@"}' + +case "$1" in +sunos-5.*) ;; +unix_sv*) ;; +irix64-*) ;; +irix-*) ;; +dgux-*) ;; +hp-ux-*) ;; +sco*) ;; +*) + echo 'ranlib "$main"' + ;; +esac diff --git a/man.do b/man.do new file mode 100644 index 0000000..d9e3f48 --- /dev/null +++ b/man.do @@ -0,0 +1,31 @@ +dependon \ +ezmlm.0 \ +ezmlm-make.0 ezmlm-manage.0 ezmlm-send.0 ezmlm-reject.0 \ +ezmlm-return.0 ezmlm-warn.0 ezmlm-weed.0 \ +ezmlm-list.0 ezmlm-sub.0 ezmlm-unsub.0 \ +alloc.0 \ +case.0 \ +datetime.0 \ +direntry.0 \ +env.0 \ +error.0 \ +error_str.0 \ +error_temp.0 \ +ezmlm.0 \ +fd_copy.0 \ +fd_move.0 \ +getln.0 \ +getln2.0 \ +getopt.0 \ +now.0 \ +sgetopt.0 \ +stralloc.0 \ +subfd.0 \ +subgetopt.0 \ +substdio.0 \ +substdio_copy.0 \ +substdio_in.0 \ +substdio_out.0 \ +surf.0 \ +surfpcs.0 \ +wait.0 diff --git a/now.3 b/now.3 new file mode 100644 index 0000000..3d845b1 --- /dev/null +++ b/now.3 @@ -0,0 +1,14 @@ +.TH now 3 +.SH NAME +now \- get current time, in seconds +.SH SYNTAX +.B #include + +datetime_sec \fBnow\fP(); +.SH DESCRIPTION +.B now +returns the number of real-time seconds that have elapsed +since the end of 1969 TAI. +.SH "SEE ALSO" +datetime(3), +time(3) diff --git a/now.c b/now.c new file mode 100644 index 0000000..5ce4d90 --- /dev/null +++ b/now.c @@ -0,0 +1,8 @@ +#include +#include "datetime.h" +#include "now.h" + +datetime_sec now() +{ + return time((long *) 0); +} diff --git a/now.h b/now.h new file mode 100644 index 0000000..b8be182 --- /dev/null +++ b/now.h @@ -0,0 +1,8 @@ +#ifndef NOW_H +#define NOW_H + +#include "datetime.h" + +extern datetime_sec now(); + +#endif diff --git a/now=0 b/now=0 new file mode 100644 index 0000000..3f02d34 --- /dev/null +++ b/now=0 @@ -0,0 +1 @@ +now.3 diff --git a/open.h b/open.h new file mode 100644 index 0000000..c903113 --- /dev/null +++ b/open.h @@ -0,0 +1,10 @@ +#ifndef OPEN_H +#define OPEN_H + +extern int open_read(); +extern int open_excl(); +extern int open_append(); +extern int open_trunc(); +extern int open_write(); + +#endif diff --git a/open=l b/open=l new file mode 100644 index 0000000..9104cd6 --- /dev/null +++ b/open=l @@ -0,0 +1,3 @@ +open_append.o +open_read.o +open_trunc.o diff --git a/open_append.c b/open_append.c new file mode 100644 index 0000000..93a0862 --- /dev/null +++ b/open_append.c @@ -0,0 +1,6 @@ +#include +#include +#include "open.h" + +int open_append(fn) char *fn; +{ return open(fn,O_WRONLY | O_NDELAY | O_APPEND | O_CREAT,0600); } diff --git a/open_read.c b/open_read.c new file mode 100644 index 0000000..f503e48 --- /dev/null +++ b/open_read.c @@ -0,0 +1,6 @@ +#include +#include +#include "open.h" + +int open_read(fn) char *fn; +{ return open(fn,O_RDONLY | O_NDELAY); } diff --git a/open_trunc.c b/open_trunc.c new file mode 100644 index 0000000..e275085 --- /dev/null +++ b/open_trunc.c @@ -0,0 +1,6 @@ +#include +#include +#include "open.h" + +int open_trunc(fn) char *fn; +{ return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); } diff --git a/qmail.c b/qmail.c new file mode 100644 index 0000000..7484331 --- /dev/null +++ b/qmail.c @@ -0,0 +1,103 @@ +#include "substdio.h" +#include "readwrite.h" +#include "wait.h" +#include "exit.h" +#include "fork.h" +#include "fd.h" +#include "qmail.h" +#include "auto_qmail.h" + +static char *binqqargs[2] = { "bin/qmail-queue", 0 } ; + +int qmail_open(qq) +struct qmail *qq; +{ + int pim[2]; + int pie[2]; + + if (pipe(pim) == -1) return -1; + if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; } + + switch(qq->pid = vfork()) { + case -1: + close(pim[0]); close(pim[1]); + close(pie[0]); close(pie[1]); + return -1; + case 0: + close(pim[1]); + close(pie[1]); + if (fd_move(0,pim[0]) == -1) _exit(120); + if (fd_move(1,pie[0]) == -1) _exit(120); + if (chdir(auto_qmail) == -1) _exit(120); + execv(*binqqargs,binqqargs); + _exit(120); + } + + qq->fdm = pim[1]; close(pim[0]); + qq->fde = pie[1]; close(pie[0]); + substdio_fdbuf(&qq->ss,write,qq->fdm,qq->buf,sizeof(qq->buf)); + qq->flagerr = 0; + return 0; +} + +unsigned long qmail_qp(qq) struct qmail *qq; +{ + return qq->pid; +} + +void qmail_fail(qq) struct qmail *qq; +{ + qq->flagerr = 1; +} + +void qmail_put(qq,s,len) struct qmail *qq; char *s; int len; +{ + if (!qq->flagerr) if (substdio_put(&qq->ss,s,len) == -1) qq->flagerr = 1; +} + +void qmail_puts(qq,s) struct qmail *qq; char *s; +{ + if (!qq->flagerr) if (substdio_puts(&qq->ss,s) == -1) qq->flagerr = 1; +} + +void qmail_from(qq,s) struct qmail *qq; char *s; +{ + if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1; + close(qq->fdm); + substdio_fdbuf(&qq->ss,write,qq->fde,qq->buf,sizeof(qq->buf)); + qmail_put(qq,"F",1); + qmail_puts(qq,s); + qmail_put(qq,"",1); +} + +void qmail_to(qq,s) struct qmail *qq; char *s; +{ + qmail_put(qq,"T",1); + qmail_puts(qq,s); + qmail_put(qq,"",1); +} + +int qmail_close(qq) +struct qmail *qq; +{ + int wstat; + + qmail_put(qq,"",1); + if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1; + close(qq->fde); + + if (wait_pid(&wstat,qq->pid) != qq->pid) return QMAIL_WAITPID; + if (wait_crashed(wstat)) return QMAIL_CRASHED; + switch(wait_exitcode(wstat)) { + case 0: if (qq->flagerr) return QMAIL_BUG; return 0; + case 112: return QMAIL_USAGE; + case 115: return QMAIL_TOOLONG; + case 103: case 104: case 105: case 106: case 108: return QMAIL_SYS; + case 121: return QMAIL_READ; + case 122: return QMAIL_WRITE; + case 123: return QMAIL_NOMEM; + case 124: return QMAIL_TIMEOUT; + case 120: return QMAIL_EXECSOFT; + default: /* 101 or 102 */ return QMAIL_BUG; + } +} diff --git a/qmail.h b/qmail.h new file mode 100644 index 0000000..7864ea1 --- /dev/null +++ b/qmail.h @@ -0,0 +1,36 @@ +#ifndef QMAIL_H +#define QMAIL_H + +#include "substdio.h" + +struct qmail { + int flagerr; + unsigned long pid; + int fdm; + int fde; + substdio ss; + char buf[1024]; +} ; + +extern int qmail_open(); +extern void qmail_put(); +extern void qmail_puts(); +extern void qmail_from(); +extern void qmail_to(); +extern void qmail_fail(); +extern int qmail_close(); +extern unsigned long qmail_qp(); + +#define QMAIL_WAITPID -2 +#define QMAIL_CRASHED -3 +#define QMAIL_USAGE -4 +#define QMAIL_BUG -5 +#define QMAIL_SYS -6 +#define QMAIL_READ -7 +#define QMAIL_WRITE -8 +#define QMAIL_NOMEM -9 +#define QMAIL_EXECSOFT -11 +#define QMAIL_TIMEOUT -13 +#define QMAIL_TOOLONG -14 + +#endif diff --git a/quote.c b/quote.c new file mode 100644 index 0000000..9f97d93 --- /dev/null +++ b/quote.c @@ -0,0 +1,82 @@ +#include "stralloc.h" +#include "str.h" +#include "quote.h" + +/* +quote() encodes a box as per rfc 821 and rfc 822, +while trying to do as little quoting as possible. +no, 821 and 822 don't have the same encoding. they're not even close. +no special encoding here for bytes above 127. +*/ + +static char ok[128] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +,0,7,0,7,7,7,7,7,0,0,7,7,0,7,7,7 ,7,7,7,7,7,7,7,7,7,7,0,0,0,7,0,7 +,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 ,7,7,7,7,7,7,7,7,7,7,7,0,0,0,7,7 +,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 ,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0 +} ; + +static int doit(saout,sain) +stralloc *saout; +stralloc *sain; +{ + char ch; + int i; + int j; + + if (!stralloc_ready(saout,sain->len * 2 + 2)) return 0; + j = 0; + saout->s[j++] = '"'; + for (i = 0;i < sain->len;++i) + { + ch = sain->s[i]; + if ((ch == '\r') || (ch == '\n') || (ch == '"') || (ch == '\\')) + saout->s[j++] = '\\'; + saout->s[j++] = ch; + } + saout->s[j++] = '"'; + saout->len = j; + return 1; +} + +int quote_need(s,n) +char *s; +unsigned int n; +{ + unsigned char uch; + int i; + if (!n) return 0; + for (i = 0;i < n;++i) + { + uch = s[i]; + if (uch >= 128) return 1; + if (!ok[uch]) return 1; + } + if (s[0] == '.') return 1; + if (s[n - 1] == '.') return 1; + for (i = 0;i < n - 1;++i) if (s[i] == '.') if (s[i + 1] == '.') return 1; + return 0; +} + +int quote(saout,sain) +stralloc *saout; +stralloc *sain; +{ + if (quote_need(sain->s,sain->len)) return doit(saout,sain); + return stralloc_copy(saout,sain); +} + +static stralloc foo = {0}; + +int quote2(sa,s) +stralloc *sa; +char *s; +{ + int j; + j = str_rchr(s,'@'); + if (!stralloc_copys(&foo,s)) return 0; + if (!s[j]) return quote(sa,&foo); + foo.len = j; + if (!quote(sa,&foo)) return 0; + return stralloc_cats(sa,s + j); +} diff --git a/quote.h b/quote.h new file mode 100644 index 0000000..8ab7356 --- /dev/null +++ b/quote.h @@ -0,0 +1,8 @@ +#ifndef QUOTE_H +#define QUOTE_H + +extern int quote_need(); +extern int quote(); +extern int quote2(); + +#endif diff --git a/readwrite.h b/readwrite.h new file mode 100644 index 0000000..2a64968 --- /dev/null +++ b/readwrite.h @@ -0,0 +1,7 @@ +#ifndef READWRITE_H +#define READWRITE_H + +extern int read(); +extern int write(); + +#endif diff --git a/scan.h b/scan.h new file mode 100644 index 0000000..53ce703 --- /dev/null +++ b/scan.h @@ -0,0 +1,27 @@ +#ifndef SCAN_H +#define SCAN_H + +extern unsigned int scan_uint(); +extern unsigned int scan_xint(); +extern unsigned int scan_nbbint(); +extern unsigned int scan_ushort(); +extern unsigned int scan_xshort(); +extern unsigned int scan_nbbshort(); +extern unsigned int scan_ulong(); +extern unsigned int scan_xlong(); +extern unsigned int scan_nbblong(); + +extern unsigned int scan_plusminus(); +extern unsigned int scan_0x(); + +extern unsigned int scan_whitenskip(); +extern unsigned int scan_nonwhitenskip(); +extern unsigned int scan_charsetnskip(); +extern unsigned int scan_noncharsetnskip(); + +extern unsigned int scan_strncmp(); +extern unsigned int scan_memcmp(); + +extern unsigned int scan_long(); + +#endif diff --git a/scan_8long.c b/scan_8long.c new file mode 100644 index 0000000..8b3a6df --- /dev/null +++ b/scan_8long.c @@ -0,0 +1,11 @@ +#include "scan.h" + +unsigned int scan_8long(s,u) register char *s; register unsigned long *u; +{ + register unsigned int pos; register unsigned long result; + register unsigned long c; + pos = 0; result = 0; + while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 8) + { result = result * 8 + c; ++pos; } + *u = result; return pos; +} diff --git a/scan_ulong.c b/scan_ulong.c new file mode 100644 index 0000000..27c41ea --- /dev/null +++ b/scan_ulong.c @@ -0,0 +1,11 @@ +#include "scan.h" + +unsigned int scan_ulong(s,u) register char *s; register unsigned long *u; +{ + register unsigned int pos; register unsigned long result; + register unsigned long c; + pos = 0; result = 0; + while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) + { result = result * 10 + c; ++pos; } + *u = result; return pos; +} diff --git a/seek.h b/seek.h new file mode 100644 index 0000000..964fba3 --- /dev/null +++ b/seek.h @@ -0,0 +1,15 @@ +#ifndef SEEK_H +#define SEEK_H + +typedef unsigned long seek_pos; + +extern seek_pos seek_cur(); + +extern int seek_set(); +extern int seek_end(); + +extern int seek_trunc(); + +#define seek_begin(fd) (seek_set((fd),(seek_pos) 0)) + +#endif diff --git a/seek=l b/seek=l new file mode 100644 index 0000000..8f34e13 --- /dev/null +++ b/seek=l @@ -0,0 +1 @@ +seek_set.o diff --git a/seek_set.c b/seek_set.c new file mode 100644 index 0000000..f540664 --- /dev/null +++ b/seek_set.c @@ -0,0 +1,7 @@ +#include +#include "seek.h" + +#define SET 0 /* sigh */ + +int seek_set(fd,pos) int fd; seek_pos pos; +{ if (lseek(fd,(off_t) pos,SET) == -1) return -1; return 0; } diff --git a/setup.do b/setup.do new file mode 100644 index 0000000..d667234 --- /dev/null +++ b/setup.do @@ -0,0 +1,5 @@ +dependon it man install conf-bin conf-man BIN MAN +formake './install "`head -1 conf-bin`" < BIN' +formake './install "`head -1 conf-man`" < MAN' +./install "`head -1 conf-bin`" < BIN +./install "`head -1 conf-man`" < MAN diff --git a/sgetopt.3 b/sgetopt.3 new file mode 100644 index 0000000..bde0c2b --- /dev/null +++ b/sgetopt.3 @@ -0,0 +1,28 @@ +.TH sgetopt 3 +.SH NAME +sgetopt \- get option character from command line +.SH SYNTAX +.B #include +.SH DESCRIPTION +The +.B sgetopt +library is just like the +.B getopt +library, +except that it prints errors using +.B substdio +rather than +.BR stdio . + +See +.B getopt(3) +for interface details. +.SH VERSION +sgetopt version 1.9, 931201. +.SH AUTHOR +Placed into the public domain by Daniel J. Bernstein. +.SH "SEE ALSO" +getopt(3), +subgetopt(3), +subfd(3), +substdio(3) diff --git a/sgetopt.c b/sgetopt.c new file mode 100644 index 0000000..a8bffc0 --- /dev/null +++ b/sgetopt.c @@ -0,0 +1,54 @@ +/* sgetopt.c, sgetopt.h: (yet another) improved getopt clone, outer layer +D. J. Bernstein, djb@pobox.com. +Depends on subgetopt.h, substdio.h, subfd.h. +No system requirements. +19970208: Cleanups. +931201: Baseline. +No known patent problems. + +Documentation in sgetopt.3. +*/ + +#include "substdio.h" +#include "subfd.h" +#define SGETOPTNOSHORT +#include "sgetopt.h" +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define getopt sgetoptmine +#define optind subgetoptind +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname + +int opterr = 1; +char *optprogname = 0; + +int getopt(argc,argv,opts) +int argc; +char **argv; +char *opts; +{ + int c; + char *s; + + if (!optprogname) { + optprogname = *argv; + if (!optprogname) optprogname = ""; + for (s = optprogname;*s;++s) if (*s == '/') optprogname = s + 1; + } + c = subgetopt(argc,argv,opts); + if (opterr) + if (c == '?') { + char chp[2]; chp[0] = optproblem; chp[1] = '\n'; + substdio_puts(subfderr,optprogname); + if (argv[optind] && (optind < argc)) + substdio_puts(subfderr,": illegal option -- "); + else + substdio_puts(subfderr,": option requires an argument -- "); + substdio_put(subfderr,chp,2); + substdio_flush(subfderr); + } + return c; +} diff --git a/sgetopt.h b/sgetopt.h new file mode 100644 index 0000000..5f89127 --- /dev/null +++ b/sgetopt.h @@ -0,0 +1,21 @@ +#ifndef SGETOPT_H +#define SGETOPT_H + +#ifndef SGETOPTNOSHORT +#define getopt sgetoptmine +#define optarg subgetoptarg +#define optind subgetoptind +#define optpos subgetoptpos +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname +#define opteof subgetoptdone +#endif + +#include "subgetopt.h" + +extern int sgetoptmine(); +extern int sgetopterr; +extern char *sgetoptprogname; + +#endif diff --git a/sgetopt=0 b/sgetopt=0 new file mode 100644 index 0000000..7291e07 --- /dev/null +++ b/sgetopt=0 @@ -0,0 +1 @@ +sgetopt.3 diff --git a/sig.h b/sig.h new file mode 100644 index 0000000..9c3a28c --- /dev/null +++ b/sig.h @@ -0,0 +1,43 @@ +#ifndef SIG_H +#define SIG_H + +extern void sig_catch(); +extern void sig_block(); +extern void sig_unblock(); +extern void sig_blocknone(); +extern void sig_pause(); + +extern void sig_dfl(); + +extern void sig_miscignore(); +extern void sig_bugcatch(); + +extern void sig_pipeignore(); +extern void sig_pipedefault(); + +extern void sig_contblock(); +extern void sig_contunblock(); +extern void sig_contcatch(); +extern void sig_contdefault(); + +extern void sig_termblock(); +extern void sig_termunblock(); +extern void sig_termcatch(); +extern void sig_termdefault(); + +extern void sig_alarmblock(); +extern void sig_alarmunblock(); +extern void sig_alarmcatch(); +extern void sig_alarmdefault(); + +extern void sig_childblock(); +extern void sig_childunblock(); +extern void sig_childcatch(); +extern void sig_childdefault(); + +extern void sig_hangupblock(); +extern void sig_hangupunblock(); +extern void sig_hangupcatch(); +extern void sig_hangupdefault(); + +#endif diff --git a/sig=l b/sig=l new file mode 100644 index 0000000..a5456da --- /dev/null +++ b/sig=l @@ -0,0 +1,2 @@ +sig_catch.o +sig_pipe.o diff --git a/sig_catch.c b/sig_catch.c new file mode 100644 index 0000000..1888765 --- /dev/null +++ b/sig_catch.c @@ -0,0 +1,18 @@ +#include +#include "sig.h" +#include "hassgact.h" + +void sig_catch(sig,f) +int sig; +void (*f)(); +{ +#ifdef HASSIGACTION + struct sigaction sa; + sa.sa_handler = f; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sig,&sa,(struct sigaction *) 0); +#else + signal(sig,f); /* won't work under System V, even nowadays---dorks */ +#endif +} diff --git a/sig_pipe.c b/sig_pipe.c new file mode 100644 index 0000000..594ae7d --- /dev/null +++ b/sig_pipe.c @@ -0,0 +1,5 @@ +#include +#include "sig.h" + +void sig_pipeignore() { sig_catch(SIGPIPE,SIG_IGN); } +void sig_pipedefault() { sig_catch(SIGPIPE,SIG_DFL); } diff --git a/slurp.c b/slurp.c new file mode 100644 index 0000000..7d50194 --- /dev/null +++ b/slurp.c @@ -0,0 +1,19 @@ +#include "stralloc.h" +#include "slurp.h" +#include "error.h" +#include "open.h" + +int slurp(fn,sa,bufsize) +char *fn; +stralloc *sa; +int bufsize; +{ + int fd; + fd = open_read(fn); + if (fd == -1) { + if (errno == error_noent) return 0; + return -1; + } + if (slurpclose(fd,sa,bufsize) == -1) return -1; + return 1; +} diff --git a/slurp.h b/slurp.h new file mode 100644 index 0000000..16aa656 --- /dev/null +++ b/slurp.h @@ -0,0 +1,6 @@ +#ifndef SLURP_H +#define SLURP_H + +extern int slurp(); + +#endif diff --git a/slurpclose.c b/slurpclose.c new file mode 100644 index 0000000..2fcef15 --- /dev/null +++ b/slurpclose.c @@ -0,0 +1,19 @@ +#include "stralloc.h" +#include "readwrite.h" +#include "slurpclose.h" +#include "error.h" + +int slurpclose(fd,sa,bufsize) +int fd; +stralloc *sa; +int bufsize; +{ + int r; + for (;;) { + if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; } + r = read(fd,sa->s + sa->len,bufsize); + if (r == -1) if (errno == error_intr) continue; + if (r <= 0) { close(fd); return r; } + sa->len += r; + } +} diff --git a/slurpclose.h b/slurpclose.h new file mode 100644 index 0000000..57e9eec --- /dev/null +++ b/slurpclose.h @@ -0,0 +1,6 @@ +#ifndef SLURPCLOSE_H +#define SLURPCLOSE_H + +extern int slurpclose(); + +#endif diff --git a/str.h b/str.h new file mode 100644 index 0000000..e00773c --- /dev/null +++ b/str.h @@ -0,0 +1,14 @@ +#ifndef STR_H +#define STR_H + +extern unsigned int str_copy(); +extern int str_diff(); +extern int str_diffn(); +extern unsigned int str_len(); +extern unsigned int str_chr(); +extern unsigned int str_rchr(); +extern int str_start(); + +#define str_equal(s,t) (!str_diff((s),(t))) + +#endif diff --git a/str=l b/str=l new file mode 100644 index 0000000..e520d2c --- /dev/null +++ b/str=l @@ -0,0 +1,13 @@ +str_len.o +str_diff.o +str_diffn.o +str_cpy.o +str_chr.o +str_rchr.o +str_start.o +byte_chr.o +byte_rchr.o +byte_diff.o +byte_copy.o +byte_cr.o +byte_zero.o diff --git a/str_chr.c b/str_chr.c new file mode 100644 index 0000000..3691826 --- /dev/null +++ b/str_chr.c @@ -0,0 +1,19 @@ +#include "str.h" + +unsigned int str_chr(s,c) +register char *s; +int c; +{ + register char ch; + register char *t; + + ch = c; + t = s; + for (;;) { + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + } + return t - s; +} diff --git a/str_cpy.c b/str_cpy.c new file mode 100644 index 0000000..453d790 --- /dev/null +++ b/str_cpy.c @@ -0,0 +1,16 @@ +#include "str.h" + +unsigned int str_copy(s,t) +register char *s; +register char *t; +{ + register int len; + + len = 0; + for (;;) { + if (!(*s = *t)) return len; ++s; ++t; ++len; + if (!(*s = *t)) return len; ++s; ++t; ++len; + if (!(*s = *t)) return len; ++s; ++t; ++len; + if (!(*s = *t)) return len; ++s; ++t; ++len; + } +} diff --git a/str_diff.c b/str_diff.c new file mode 100644 index 0000000..18f8927 --- /dev/null +++ b/str_diff.c @@ -0,0 +1,17 @@ +#include "str.h" + +int str_diff(s,t) +register char *s; +register char *t; +{ + register char x; + + for (;;) { + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + } + return ((int)(unsigned int)(unsigned char) x) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/str_diffn.c b/str_diffn.c new file mode 100644 index 0000000..89142f1 --- /dev/null +++ b/str_diffn.c @@ -0,0 +1,18 @@ +#include "str.h" + +int str_diffn(s,t,len) +register char *s; +register char *t; +unsigned int len; +{ + register char x; + + for (;;) { + if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + } + return ((int)(unsigned int)(unsigned char) x) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/str_len.c b/str_len.c new file mode 100644 index 0000000..2d2f88b --- /dev/null +++ b/str_len.c @@ -0,0 +1,15 @@ +#include "str.h" + +unsigned int str_len(s) +register char *s; +{ + register char *t; + + t = s; + for (;;) { + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + } +} diff --git a/str_rchr.c b/str_rchr.c new file mode 100644 index 0000000..1bf19d3 --- /dev/null +++ b/str_rchr.c @@ -0,0 +1,22 @@ +#include "str.h" + +unsigned int str_rchr(s,c) +register char *s; +int c; +{ + register char ch; + register char *t; + register char *u; + + ch = c; + t = s; + u = 0; + for (;;) { + if (!*t) break; if (*t == ch) u = t; ++t; + if (!*t) break; if (*t == ch) u = t; ++t; + if (!*t) break; if (*t == ch) u = t; ++t; + if (!*t) break; if (*t == ch) u = t; ++t; + } + if (!u) u = t; + return u - s; +} diff --git a/str_start.c b/str_start.c new file mode 100644 index 0000000..2750af8 --- /dev/null +++ b/str_start.c @@ -0,0 +1,15 @@ +#include "str.h" + +int str_start(s,t) +register char *s; +register char *t; +{ + register char x; + + for (;;) { + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + } +} diff --git a/stralloc.3 b/stralloc.3 new file mode 100644 index 0000000..3123521 --- /dev/null +++ b/stralloc.3 @@ -0,0 +1,160 @@ +.TH stralloc 3 +.SH NAME +stralloc \- dynamically allocated strings +.SH SYNTAX +.B #include + +int \fBstralloc_ready\fP(&\fIsa\fR,\fIlen\fR); +.br +int \fBstralloc_readyplus\fP(&\fIsa\fR,\fIlen\fR); + +int \fBstralloc_copy\fP(&\fIsa\fR,&\fIsa2\fR); +.br +int \fBstralloc_copys\fP(&\fIsa\fR,\fIbuf\fR); +.br +int \fBstralloc_copyb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); + +int \fBstralloc_cat\fP(&\fIsa\fR,&\fIsa2\fR); +.br +int \fBstralloc_cats\fP(&\fIsa\fR,\fIbuf\fR); +.br +int \fBstralloc_catb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); + +int \fBstralloc_append\fP(&\fIsa\fR,\fIbuf\fR); +.br +int \fBstralloc_0\fP(&\fIsa\fR); + +int \fBstralloc_starts\fP(&\fIsa\fR,\fIbuf\fR); + +stralloc \fIsa\fR = {0}; +.br +stralloc \fIsa2\fR = {0}; +.br +unsigned int \fIlen\fR; +.br +char *\fIbuf\fR; +.SH DESCRIPTION +A +.B stralloc +variable holds a string in dynamically allocated space. +String length is limited only by memory. +String contents are unrestricted. + +The +.B stralloc +structure has three components: +.I sa\fB.s +is a pointer to the string, or 0 if it is not allocated; +.I sa\fB.len +is the number of bytes in the string, if it is allocated; +.I sa\fB.a +is the number of bytes allocated for the string, if it is allocated. +A +.B stralloc +variable should be initialized to {0}, +meaning unallocated. + +.B stralloc_ready +makes sure that +.I sa +has enough space allocated for +.I len +characters. +It allocates extra space if necessary. + +.B stralloc_readyplus +makes sure that +.I sa +has enough space allocated for +.I len +characters more than its current length. +If +.I sa +is unallocated, +.B stralloc_readyplus +is the same as +.BR stralloc_ready . + +.B stralloc_copy +copies +.I sa2 +to +.IR sa , +allocating space if necessary. +Here +.I sa2 +is an allocated +.B stralloc +variable. + +.B stralloc_copys +copies a 0-terminated string, +.IR buf , +to +.IR sa , +without the 0. + +.B stralloc_copyb +copies +.I len +characters from +.I buf +to +.IR sa . + +.B stralloc_cat +appends +.I sa2 +to +.IR sa , +allocating space if necessary. +If +.I sa +is unallocated, +.B stralloc_cat +is the same as +.BR stralloc_copy . + +.B stralloc_cats +and +.B stralloc_catb +are analogous to +.B stralloc_copys +and +.BR stralloc_copyb . + +.B stralloc_append +adds a single character, +.IR *buf , +to +.IR sa , +allocating space if necessary. + +.B stralloc_0 +adds a single 0 character +to +.IR sa . + +.B stralloc_starts +returns 1 if the 0-terminated string +.IR buf , +without the 0, +is a prefix of +.IR sa . +.SH "ERROR HANDLING" +If a +.B stralloc +routine runs out of memory, +it leaves +.I sa +alone and returns 0, +setting +.B errno +appropriately. +On success it returns 1; +this guarantees that +.I sa +is allocated. +.SH "SEE ALSO" +alloc(3), +error(3) diff --git a/stralloc.h b/stralloc.h new file mode 100644 index 0000000..fca496c --- /dev/null +++ b/stralloc.h @@ -0,0 +1,21 @@ +#ifndef STRALLOC_H +#define STRALLOC_H + +#include "gen_alloc.h" + +GEN_ALLOC_typedef(stralloc,char,s,len,a) + +extern int stralloc_ready(); +extern int stralloc_readyplus(); +extern int stralloc_copy(); +extern int stralloc_cat(); +extern int stralloc_copys(); +extern int stralloc_cats(); +extern int stralloc_copyb(); +extern int stralloc_catb(); +extern int stralloc_append(); /* beware: this takes a pointer to 1 char */ +extern int stralloc_starts(); + +#define stralloc_0(sa) stralloc_append(sa,"") + +#endif diff --git a/stralloc=0 b/stralloc=0 new file mode 100644 index 0000000..12889aa --- /dev/null +++ b/stralloc=0 @@ -0,0 +1 @@ +stralloc.3 diff --git a/stralloc=l b/stralloc=l new file mode 100644 index 0000000..6aac39b --- /dev/null +++ b/stralloc=l @@ -0,0 +1,9 @@ +stralloc_eady.o +stralloc_pend.o +stralloc_copy.o +stralloc_opys.o +stralloc_opyb.o +stralloc_cat.o +stralloc_cats.o +stralloc_catb.o +stralloc_arts.o diff --git a/stralloc_arts.c b/stralloc_arts.c new file mode 100644 index 0000000..1ccb5a4 --- /dev/null +++ b/stralloc_arts.c @@ -0,0 +1,12 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_starts(sa,s) +stralloc *sa; +char *s; +{ + int len; + len = str_len(s); + return (sa->len >= len) && byte_equal(s,len,sa->s); +} diff --git a/stralloc_cat.c b/stralloc_cat.c new file mode 100644 index 0000000..efbb112 --- /dev/null +++ b/stralloc_cat.c @@ -0,0 +1,9 @@ +#include "byte.h" +#include "stralloc.h" + +int stralloc_cat(sato,safrom) +stralloc *sato; +stralloc *safrom; +{ + return stralloc_catb(sato,safrom->s,safrom->len); +} diff --git a/stralloc_catb.c b/stralloc_catb.c new file mode 100644 index 0000000..67dbcc0 --- /dev/null +++ b/stralloc_catb.c @@ -0,0 +1,15 @@ +#include "stralloc.h" +#include "byte.h" + +int stralloc_catb(sa,s,n) +stralloc *sa; +char *s; +unsigned int n; +{ + if (!sa->s) return stralloc_copyb(sa,s,n); + if (!stralloc_readyplus(sa,n + 1)) return 0; + byte_copy(sa->s + sa->len,n,s); + sa->len += n; + sa->s[sa->len] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_cats.c b/stralloc_cats.c new file mode 100644 index 0000000..d300286 --- /dev/null +++ b/stralloc_cats.c @@ -0,0 +1,10 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_cats(sa,s) +stralloc *sa; +char *s; +{ + return stralloc_catb(sa,s,str_len(s)); +} diff --git a/stralloc_copy.c b/stralloc_copy.c new file mode 100644 index 0000000..652aed6 --- /dev/null +++ b/stralloc_copy.c @@ -0,0 +1,9 @@ +#include "byte.h" +#include "stralloc.h" + +int stralloc_copy(sato,safrom) +stralloc *sato; +stralloc *safrom; +{ + return stralloc_copyb(sato,safrom->s,safrom->len); +} diff --git a/stralloc_eady.c b/stralloc_eady.c new file mode 100644 index 0000000..3a31f4b --- /dev/null +++ b/stralloc_eady.c @@ -0,0 +1,6 @@ +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready) +GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus) diff --git a/stralloc_opyb.c b/stralloc_opyb.c new file mode 100644 index 0000000..ac258b3 --- /dev/null +++ b/stralloc_opyb.c @@ -0,0 +1,14 @@ +#include "stralloc.h" +#include "byte.h" + +int stralloc_copyb(sa,s,n) +stralloc *sa; +char *s; +unsigned int n; +{ + if (!stralloc_ready(sa,n + 1)) return 0; + byte_copy(sa->s,n,s); + sa->len = n; + sa->s[n] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_opys.c b/stralloc_opys.c new file mode 100644 index 0000000..fdd7807 --- /dev/null +++ b/stralloc_opys.c @@ -0,0 +1,10 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_copys(sa,s) +stralloc *sa; +char *s; +{ + return stralloc_copyb(sa,s,str_len(s)); +} diff --git a/stralloc_pend.c b/stralloc_pend.c new file mode 100644 index 0000000..a3443b8 --- /dev/null +++ b/stralloc_pend.c @@ -0,0 +1,5 @@ +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append) diff --git a/strerr.c b/strerr.c new file mode 100644 index 0000000..a6bc00c --- /dev/null +++ b/strerr.c @@ -0,0 +1,22 @@ +#include "stralloc.h" +#include "strerr.h" + +static stralloc sa = {0}; + +char *strerr(se) +struct strerr *se; +{ + strerr_sysinit(); + + if (!stralloc_copys(&sa,"")) return "out of memory"; + + while(se) { + if (se->x) if (!stralloc_cats(&sa,se->x)) return "out of memory"; + if (se->y) if (!stralloc_cats(&sa,se->y)) return "out of memory"; + if (se->z) if (!stralloc_cats(&sa,se->z)) return "out of memory"; + se = se->who; + } + + if (!stralloc_0(&sa)) return "out of memory"; + return sa.s; +} diff --git a/strerr.h b/strerr.h new file mode 100644 index 0000000..d18e833 --- /dev/null +++ b/strerr.h @@ -0,0 +1,80 @@ +#ifndef STRERR_H +#define STRERR_H + +struct strerr + { + struct strerr *who; + char *x; + char *y; + char *z; + } +; + +extern struct strerr strerr_sys; +extern void strerr_sysinit(); + +extern char *strerr(); +extern void strerr_warn(); +extern void strerr_die(); + +#define STRERR(r,se,a) \ +{ se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; } + +#define STRERR_SYS(r,se,a) \ +{ se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; } +#define STRERR_SYS3(r,se,a,b,c) \ +{ se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; } + +#define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se)) +#define strerr_warn5(x1,x2,x3,x4,x5,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se)) +#define strerr_warn4(x1,x2,x3,x4,se) \ +strerr_warn((x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_warn3(x1,x2,x3,se) \ +strerr_warn((x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_warn2(x1,x2,se) \ +strerr_warn((x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_warn1(x1,se) \ +strerr_warn((x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) + +#define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se)) +#define strerr_die5(e,x1,x2,x3,x4,x5,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se)) +#define strerr_die4(e,x1,x2,x3,x4,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_die3(e,x1,x2,x3,se) \ +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_die2(e,x1,x2,se) \ +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_die1(e,x1,se) \ +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) + +#define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys) +#define strerr_die5sys(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,&strerr_sys) +#define strerr_die4sys(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,&strerr_sys) +#define strerr_die3sys(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,&strerr_sys) +#define strerr_die2sys(e,x1,x2) \ +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys) +#define strerr_die1sys(e,x1) \ +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys) + +#define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) 0) +#define strerr_die5x(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) 0) +#define strerr_die4x(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) 0) +#define strerr_die3x(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) +#define strerr_die2x(e,x1,x2) \ +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) +#define strerr_die1x(e,x1) \ +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) + +#endif diff --git a/strerr=l b/strerr=l new file mode 100644 index 0000000..f3580a1 --- /dev/null +++ b/strerr=l @@ -0,0 +1,3 @@ +strerr.o +strerr_sys.o +strerr_die.o diff --git a/strerr_die.c b/strerr_die.c new file mode 100644 index 0000000..6092020 --- /dev/null +++ b/strerr_die.c @@ -0,0 +1,37 @@ +#include "substdio.h" +#include "subfd.h" +#include "exit.h" +#include "strerr.h" + +void strerr_warn(x1,x2,x3,x4,x5,x6,se) +char *x1; char *x2; char *x3; char *x4; char *x5; char *x6; +struct strerr *se; +{ + strerr_sysinit(); + + if (x1) substdio_puts(subfderr,x1); + if (x2) substdio_puts(subfderr,x2); + if (x3) substdio_puts(subfderr,x3); + if (x4) substdio_puts(subfderr,x4); + if (x5) substdio_puts(subfderr,x5); + if (x6) substdio_puts(subfderr,x6); + + while(se) { + if (se->x) substdio_puts(subfderr,se->x); + if (se->y) substdio_puts(subfderr,se->y); + if (se->z) substdio_puts(subfderr,se->z); + se = se->who; + } + + substdio_puts(subfderr,"\n"); + substdio_flush(subfderr); +} + +void strerr_die(e,x1,x2,x3,x4,x5,x6,se) +int e; +char *x1; char *x2; char *x3; char *x4; char *x5; char *x6; +struct strerr *se; +{ + strerr_warn(x1,x2,x3,x4,x5,x6,se); + _exit(e); +} diff --git a/strerr_sys.c b/strerr_sys.c new file mode 100644 index 0000000..198198b --- /dev/null +++ b/strerr_sys.c @@ -0,0 +1,12 @@ +#include "error.h" +#include "strerr.h" + +struct strerr strerr_sys; + +void strerr_sysinit() +{ + strerr_sys.who = 0; + strerr_sys.x = error_str(errno); + strerr_sys.y = ""; + strerr_sys.z = ""; +} diff --git a/subfd.3 b/subfd.3 new file mode 100644 index 0000000..6859e64 --- /dev/null +++ b/subfd.3 @@ -0,0 +1,61 @@ +.TH subfd 3 +.SH NAME +subfd \- standard input, output, error for substdio +.SH SYNTAX +.B #include + +substdio *\fBsubfdin\fP; +.br +substdio *\fBsubfdout\fP; +.br +substdio *\fBsubfderr\fP; + +int \fBsubfd_read\fP(\fIfd\fR,\fIbuf\fR,\fIlen\fR); + +substdio *\fBsubfdinsmall\fP; +.br +substdio *\fBsubfdoutsmall\fP; + +int \fBsubfd_readsmall\fP(\fIfd\fR,\fIbuf\fR,\fIlen\fR); + +int \fIfd\fR; +.br +char *\fIbuf\fR; +.br +int \fIlen\fR; +.SH DESCRIPTION +.B subfderr +writes data to descriptor 2. + +.B subfdout +writes data to descriptor 1. + +.B subfdin +reads data from descriptor 0. +It coordinates with +.BR subfdout : +it flushes +.B subfdout +before refilling its buffer. +This eliminates the need for +.B subfdout +flushing in most programs. +To set up the same flushing mechanism for another input descriptor, +use +.B subfd_read +in place of +.BR read . + +.BR subfdoutsmall , +.BR subfd_readsmall , +and +.B subfdinsmall +behave the same way as +.BR subfdout , +.BR subfd_read , +and +.BR subfdin , +except that they use small (256-byte) buffers. +This is appropriate for programs that read data in small chunks. +.SH "SEE ALSO" +substdio(3) diff --git a/subfd.h b/subfd.h new file mode 100644 index 0000000..bcb2e1e --- /dev/null +++ b/subfd.h @@ -0,0 +1,15 @@ +#ifndef SUBFD_H +#define SUBFD_H + +#include "substdio.h" + +extern substdio *subfdin; +extern substdio *subfdinsmall; +extern substdio *subfdout; +extern substdio *subfdoutsmall; +extern substdio *subfderr; + +extern int subfd_read(); +extern int subfd_readsmall(); + +#endif diff --git a/subfd=0 b/subfd=0 new file mode 100644 index 0000000..9e10976 --- /dev/null +++ b/subfd=0 @@ -0,0 +1 @@ +subfd.3 diff --git a/subfderr.c b/subfderr.c new file mode 100644 index 0000000..011ab0f --- /dev/null +++ b/subfderr.c @@ -0,0 +1,7 @@ +#include "readwrite.h" +#include "substdio.h" +#include "subfd.h" + +char subfd_errbuf[256]; +static substdio it = SUBSTDIO_FDBUF(write,2,subfd_errbuf,256); +substdio *subfderr = ⁢ diff --git a/subgetopt.3 b/subgetopt.3 new file mode 100644 index 0000000..aae03aa --- /dev/null +++ b/subgetopt.3 @@ -0,0 +1,357 @@ +.TH subgetopt 3 +.SH NAME +subgetopt \- get option character from command line +.SH SYNTAX +.B #include + +char *\fBsgoptarg\fP; +.br +int \fBsgoptind\fP; +.br +int \fBsgoptpos\fP; +.br +int \fBsgoptdone\fP; +.br +int \fBsgoptproblem\fP; + +int \fBsgopt(\fP\fIargc,argv,opts\fR\fB)\fP; + +int \fIargc\fR; +.br +char **\fIargv\fR; +.br +char *\fIopts\fR; +.SH DESCRIPTION +.B sgopt +returns the next valid command-line option character +from +.IR argv . + +Valid option characters are listed in the +.I opts +string. +.I opts +may be empty. +A character in +.I opts +may be followed by a colon, +in which case it +takes an +.I option argument\fR. +Avoid using the characters ?, :, and \- as option characters. + +Below +.I option argument +is abbreviated +as +.I optarg +and +.I command-line argument +is abbreviated as +.IR cmdarg . + +Options are listed in cmdargs which begin with +a minus sign. +Several options which do not take optargs may be combined +into one cmdarg. + +An option which takes an optarg may be handled in two ways. +If it appears at the very end of a cmdarg, +then the entire next cmdarg is the optarg. +But if there are any characters in the cmdarg +after the option character, +then those characters form the optarg. +The optarg is returned in +.BR sgoptarg . +Next time +.B sgopt +looks at the cmdarg which follows the optarg. + +If a cmdarg does not begin with a hyphen, +or if it is a lone hyphen not followed by any characters, +or if it begins with two hyphens, +then it terminates option processing, +and +.B sgopt +returns an appropriate code. +If there are two hyphens, +.B sgopt +will advance attention to the next cmdarg, +so it can be called again to read further options. +.SH "PROPER USAGE" +.B sgoptproblem +should be used only when +.B sgopt +returns ?. +.B sgoptind +and +.B sgoptpos +are defined all the time. +.B sgoptarg +is defined all the time; +it is null unless +.B sgopt +has just returned an option with optarg. + +.B sgopt +is typically used as follows. + +.EX +#include + +main(argc,argv) int argc; char **argv; { int opt; + +while ((opt = sgopt(argc,argv,"a:s")) != sgoptdone) +.br + switch(opt) { +.br + case 'a': +.br + printf("opt a with optarg %s\\n",sgoptarg); break; +.br + case 's': +.br + printf("opt s with no optarg\\n"); break; +.br + case '?': +.br + if (argv[sgoptind] && (sgoptind < argc)) +.br + printf("illegal opt %c\\n",sgoptproblem); +.br + else +.br + printf("missing arg, opt %c\\n",sgoptproblem); +.br + exit(1); +.br + } + +argv += sgoptind; +.br +while (*argv) printf("argument %s\\n",*argv++); +.br +exit(0); +.br +} +.EE + +The end of the command line is +marked by either +.IR argc , +or a null pointer in +.IR argv , +whichever comes first. +Normally +these two markers coincide, +so it is redundant +to test for +both +.I argv\fB[sgoptind] +and +.B sgoptind < \fIargc\fR. +The above code shows both tests as an illustration. + +.B Multiple option sets: +One useful technique is to call +.B sgopt +with a primary +.I opts +until it returns EOF, +then call +.B sgopt +with a secondary +.I opts +until it returns EOF. +The user can provide primary options, then a double hyphen, +and then secondary options. +No special handling is needed if some or all of the options are +omitted. +The same technique can be used for any number of option sets +in series. + +.B Multiple command lines: +Before parsing a new +.BR argv , +make sure to +set +.B sgoptind +and +.B sgoptpos +back to +1 and 0. +.SH "PARSING STAGES" +.B sgopt +keeps track of its position in +.I argv +with +.B sgoptind +and +.BR sgoptpos , +which are initialized to 1 and 0. +It looks at +.I argv\fB[sgoptind][sgoptpos] +and following characters. + +.B sgopt +indicates +that no more options are available by +returning +.BR sgoptdone , +which is initialized to +.BR SUBGETOPTDONE , +which is defined as \-1. + +.B sgopt +begins by setting +.B optarg +to null. + +.B Ending conditions: +If +.I argv +is null, or +.B sgoptind +is larger than +.IR argc , +or the current cmdarg +.I argv\fB[sgoptind] +is null, +then +.B sgopt +returns +.BR optdone . + +.B Stage one: +If the current character +is zero, +.B sgopt +moves to the beginning of the next cmdarg. +It then checks the ending conditions again. + +.B Stage two: +If +the current position is the begining of the cmdarg, +.B sgopt +checks whether +the current character +is a minus sign. +If not it returns +.BR optdone . +It then +moves +to the next character. +If that character is zero, +.B sgopt +moves +back to the beginning of the cmdarg, +and returns +.BR sgoptdone . +If the character is a minus sign, +.B sgopt +moves to the beginning of the next cmdarg, +and returns +.BR sgoptdone . + +.B Stage three: +.B sgopt +records the current character, +.IR c , +and moves to the next character. +There are three possibilities: +(1) +.I c +is an option character without optarg in +.IR opts , +or +(2) +.I c +is an option character with optarg in +.IR opts , +or +(3) +.I c +does not appear in +.IR opts . + +(1) +If +.I c +appears as an option character without optarg in +.IR opts , +.B sgopt +returns +.IR c . + +(2) +If +.I c +appears as an option character with optarg in +.IR opts , +.B sgopt +sets +.B sgoptarg +to the current position, +and moves to the next cmdarg. +If +.B sgoptarg +is nonempty, +.B sgopt +returns +.IR c . + +Then +.B sgopt +sets +.B sgoptarg +to +the current cmdarg. +If +the current cmdarg is null, +or past +.IR argc , +.B sgopt +sets +.B sgoptproblem +to +.I c +and returns ?. +Otherwise +.B sgopt +moves to the next +argument +and returns +.IR c . + +(2) +If +.I c +does not appear in +.IR opts , +.B sgopt +sets +.B sgoptproblem +to +.I c +and returns ?. +.SH "SYNTAX NOTE" +.B sgopt +is actually a macro abbreviation for +.BR subgetopt . +The external +.B sg +variables are also macros +for +.BR subget . +These macros are defined in +.BR , +unless +.B SUBGETOPTNOSHORT +is defined +when +.B +is included. +.SH VERSION +subgetopt version 0.9, 931129. +.SH AUTHOR +Placed into the public domain by Daniel J. Bernstein. diff --git a/subgetopt.c b/subgetopt.c new file mode 100644 index 0000000..dacf376 --- /dev/null +++ b/subgetopt.c @@ -0,0 +1,79 @@ +/* subgetopt.c, subgetopt.h: (yet another) improved getopt clone, inner layer +D. J. Bernstein, djb@pobox.com. +No dependencies. +No system requirements. +19970228: Cleanups. +931129: Adapted from getopt.c. +No known patent problems. + +Documentation in subgetopt.3. +*/ + +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define sgopt subgetopt +#define optind subgetoptind +#define optpos subgetoptpos +#define optarg subgetoptarg +#define optproblem subgetoptproblem +#define optdone subgetoptdone + +int optind = 1; +int optpos = 0; +char *optarg = 0; +int optproblem = 0; +int optdone = SUBGETOPTDONE; + +int sgopt(argc,argv,opts) +int argc; +char **argv; +char *opts; +{ + int c; + char *s; + + optarg = 0; + if (!argv || (optind >= argc) || !argv[optind]) return optdone; + if (optpos && !argv[optind][optpos]) { + ++optind; + optpos = 0; + if ((optind >= argc) || !argv[optind]) return optdone; + } + if (!optpos) { + if (argv[optind][0] != '-') return optdone; + ++optpos; + c = argv[optind][1]; + if ((c == '-') || (c == 0)) { + if (c) ++optind; + optpos = 0; + return optdone; + } + /* otherwise c is reassigned below */ + } + c = argv[optind][optpos]; + ++optpos; + s = opts; + while (*s) { + if (c == *s) { + if (s[1] == ':') { + optarg = argv[optind] + optpos; + ++optind; + optpos = 0; + if (!*optarg) { + optarg = argv[optind]; + if ((optind >= argc) || !optarg) { /* argument past end */ + optproblem = c; + return '?'; + } + ++optind; + } + } + return c; + } + ++s; + if (*s == ':') ++s; + } + optproblem = c; + return '?'; +} diff --git a/subgetopt.h b/subgetopt.h new file mode 100644 index 0000000..d26c62a --- /dev/null +++ b/subgetopt.h @@ -0,0 +1,24 @@ +#ifndef SUBGETOPT_H +#define SUBGETOPT_H + +#ifndef SUBGETOPTNOSHORT +#define sgopt subgetopt +#define sgoptarg subgetoptarg +#define sgoptind subgetoptind +#define sgoptpos subgetoptpos +#define sgoptproblem subgetoptproblem +#define sgoptprogname subgetoptprogname +#define sgoptdone subgetoptdone +#endif + +#define SUBGETOPTDONE -1 + +extern int subgetopt(); +extern char *subgetoptarg; +extern int subgetoptind; +extern int subgetoptpos; +extern int subgetoptproblem; +extern char *subgetoptprogname; +extern int subgetoptdone; + +#endif diff --git a/subgetopt=0 b/subgetopt=0 new file mode 100644 index 0000000..38ed342 --- /dev/null +++ b/subgetopt=0 @@ -0,0 +1 @@ +subgetopt.3 diff --git a/subscribe.c b/subscribe.c new file mode 100644 index 0000000..fee21e2 --- /dev/null +++ b/subscribe.c @@ -0,0 +1,127 @@ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "strerr.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "lock.h" +#include "error.h" +#include "uint32.h" +#include "subscribe.h" + +static stralloc addr = {0}; +static stralloc line = {0}; +static stralloc fnnew = {0}; +static stralloc fn = {0}; + +static int fd; +static substdio ss; +static char ssbuf[256]; +static int fdnew; +static substdio ssnew; +static char ssnewbuf[256]; + +static int doit(userhost,flagadd) +char *userhost; +int flagadd; +{ + int j; + uint32 h; + char ch; + int match; + int flagwasthere; + + if (userhost[str_chr(userhost,'\n')]) return -8; + if (!stralloc_copys(&addr,"T")) return -2; + if (!stralloc_cats(&addr,userhost)) return -2; + if (addr.len > 401) return -7; + + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) return -6; + case_lowerb(addr.s + j + 1,addr.len - j - 1); + + h = 5381; + for (j = 0;j < addr.len;++j) + h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; + ch = 64 + (h % 53); + + if (!stralloc_0(&addr)) return -2; + + if (!stralloc_copys(&fn,"subscribers/")) return -2; + if (!stralloc_catb(&fn,&ch,1)) return -2; + if (!stralloc_copy(&fnnew,&fn)) return -2; + if (!stralloc_cats(&fnnew,"n")) return -2; + if (!stralloc_0(&fnnew)) return -2; + if (!stralloc_0(&fn)) return -2; + + fdnew = open_trunc(fnnew.s); + if (fdnew == -1) return -4; + substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); + + flagwasthere = 0; + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) { close(fdnew); return -3; } + } + else { + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) { close(fd); close(fdnew); return -3; } + if (!match) break; + if (line.len == addr.len) + if (!byte_diff(line.s,line.len,addr.s)) { + flagwasthere = 1; + if (!flagadd) + continue; + } + if (substdio_bput(&ssnew,line.s,line.len) == -1) { close(fd); close(fdnew); return -4; } + } + + close(fd); + } + + if (flagadd && !flagwasthere) + if (substdio_bput(&ssnew,addr.s,addr.len) == -1) { close(fdnew); return -4; } + + if (substdio_flush(&ssnew) == -1) { close(fdnew); return -4; } + if (fsync(fdnew) == -1) { close(fdnew); return -4; } + close(fdnew); + + if (rename(fnnew.s,fn.s) == -1) return -5; + return flagadd ^ flagwasthere; +} + +struct strerr subscribe_err; + +int subscribe(userhost,flagadd) +char *userhost; +int flagadd; +{ + int fdlock; + int r; + + fdlock = open_append("lock"); + if (fdlock == -1) + STRERR_SYS(-1,subscribe_err,"unable to open lock: ") + if (lock_ex(fdlock) == -1) { + close(fdlock); + STRERR_SYS(-1,subscribe_err,"unable to obtain lock: ") + } + + r = doit(userhost,flagadd); + close(fdlock); + + if (r == -2) STRERR(-1,subscribe_err,"out of memory") + if (r == -3) STRERR_SYS3(-1,subscribe_err,"unable to read ",fn.s,": ") + if (r == -4) STRERR_SYS3(-1,subscribe_err,"unable to write ",fnnew.s,": ") + if (r == -5) STRERR_SYS3(-1,subscribe_err,"unable to move temporary file to ",fn.s,": ") + if (r == -6) STRERR(-2,subscribe_err,"address does not contain @") + if (r == -7) STRERR(-2,subscribe_err,"address is too long") + if (r == -8) STRERR(-2,subscribe_err,"address contains newline") + + return r; +} diff --git a/subscribe.h b/subscribe.h new file mode 100644 index 0000000..48a2f1c --- /dev/null +++ b/subscribe.h @@ -0,0 +1,10 @@ +#ifndef SUBSCRIBE_H +#define SUBSCRIBE_H + +#include "strerr.h" + +extern struct strerr subscribe_err; + +extern int subscribe(); + +#endif diff --git a/substdi.c b/substdi.c new file mode 100644 index 0000000..42407a1 --- /dev/null +++ b/substdi.c @@ -0,0 +1,91 @@ +#include "substdio.h" +#include "byte.h" +#include "error.h" + +static int oneread(op,fd,buf,len) +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int r; + + for (;;) { + r = op(fd,buf,len); + if (r == -1) if (errno == error_intr) continue; + return r; + } +} + +static int getthis(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int r; + register int q; + + r = s->p; + q = r - len; + if (q > 0) { r = len; s->p = q; } else s->p = 0; + byte_copy(buf,r,s->x + s->n); + s->n += r; + return r; +} + +int substdio_feed(s) +register substdio *s; +{ + register int r; + register int q; + + if (s->p) return s->p; + q = s->n; + r = oneread(s->op,s->fd,s->x,q); + if (r <= 0) return r; + s->p = r; + q -= r; + s->n = q; + if (q > 0) /* damn, gotta shift */ byte_copyr(s->x + q,r,s->x); + return r; +} + +int substdio_bget(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int r; + + if (s->p > 0) return getthis(s,buf,len); + r = s->n; if (r <= len) return oneread(s->op,s->fd,buf,r); + r = substdio_feed(s); if (r <= 0) return r; + return getthis(s,buf,len); +} + +int substdio_get(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int r; + + if (s->p > 0) return getthis(s,buf,len); + if (s->n <= len) return oneread(s->op,s->fd,buf,len); + r = substdio_feed(s); if (r <= 0) return r; + return getthis(s,buf,len); +} + +char *substdio_peek(s) +register substdio *s; +{ + return s->x + s->n; +} + +void substdio_seek(s,len) +register substdio *s; +register int len; +{ + s->n += len; + s->p -= len; +} diff --git a/substdio.3 b/substdio.3 new file mode 100644 index 0000000..2bb459d --- /dev/null +++ b/substdio.3 @@ -0,0 +1,115 @@ +.TH substdio 3 +.SH NAME +substdio \- the Sub-Standard Input/Output Library +.SH SYNTAX +.B #include + +void \fBsubstdio_fdbuf\fP(&\fIs\fR,\fIop\fR,\fIfd\fR,\fIbuf\fR,\fIlen\fR); + +int \fBsubstdio_fileno\fP(&\fIs\fR); + +substdio \fIs\fR; +.br +int (*\fIop\fR)(); +.br +int \fIfd\fR; +.br +char *\fIbuf\fR; +.br +int \fIlen\fR; +.SH DESCRIPTION +.B substdio +is the Sub-Standard I/O Library. +.B substdio +contains only a few of the features of stdio; +it is a fast, lightweight, low-level library, +suitable for use as a component of higher-level I/O libraries. + +The point of +.B substdio +is to provide buffered I/O. +The basic object in +.B substdio +is the +.B substdio +structure; +a +.B substdio +variable stores +an operation, +a descriptor, +and +a pointer into a buffer of some nonzero length. +The +.B substdio +operations read data from the buffer, +filling the buffer as necessary using the operation on the descriptor, +or write data to the buffer, +flushing the buffer as necessary using the operation on the descriptor. +Input and output operations cannot be mixed. + +.B substdio_fdbuf +initializes a +.B substdio +variable. +The operation is +.IR op . +The descriptor is +.IR fd . +The buffer is +.IR buf , +an array of +.I len +chars. + +.I op +will be called as +.I op\fR(\fIfd\fR,\fIx\fR,\fIn\fR). +Here +.I x +is a pointer to an array of characters of length +.IR n ; +.I op +must read some characters from +.I fd +to that array, or write some characters to +.I fd +from that array. +The return value from +.I op +must be the number of characters read or written. +0 characters read means end of input; +0 characters written means that the write operation +should be tried again immediately. +On error, +.I op +must return -1, +setting +.B errno +appropriately, without reading or writing anything. +Most errors are returned directly to the +.B substdio +caller, but an error of +.B error_intr +means that the operation should be tried again immediately. + +There is a +.B SUBSTDIO_FDBUF +macro that can be used to statically initialize a +.B substdio +variable: + +.EX + substdio s = SUBSTDIO_FDBUF(op,fd,buf,len); +.EE + +.B substdio_fileno +returns the +descriptor for an initialized +.B substdio +variable. +.SH "SEE ALSO" +substdio_in(3), +substdio_out(3), +substdio_copy(3), +error(3) diff --git a/substdio.c b/substdio.c new file mode 100644 index 0000000..d03dff2 --- /dev/null +++ b/substdio.c @@ -0,0 +1,15 @@ +#include "substdio.h" + +void substdio_fdbuf(s,op,fd,buf,len) +register substdio *s; +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + s->x = buf; + s->fd = fd; + s->op = op; + s->p = 0; + s->n = len; +} diff --git a/substdio.h b/substdio.h new file mode 100644 index 0000000..c3f7f7d --- /dev/null +++ b/substdio.h @@ -0,0 +1,47 @@ +#ifndef SUBSTDIO_H +#define SUBSTDIO_H + +typedef struct substdio { + char *x; + int p; + int n; + int fd; + int (*op)(); +} substdio; + +#define SUBSTDIO_FDBUF(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } + +extern void substdio_fdbuf(); + +extern int substdio_flush(); +extern int substdio_put(); +extern int substdio_bput(); +extern int substdio_putflush(); +extern int substdio_puts(); +extern int substdio_bputs(); +extern int substdio_putsflush(); + +extern int substdio_get(); +extern int substdio_bget(); +extern int substdio_feed(); + +extern char *substdio_peek(); +extern void substdio_seek(); + +#define substdio_fileno(s) ((s)->fd) + +#define SUBSTDIO_INSIZE 8192 +#define SUBSTDIO_OUTSIZE 8192 + +#define substdio_PEEK(s) ( (s)->x + (s)->n ) +#define substdio_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) + +#define substdio_BPUTC(s,c) \ + ( ((s)->n != (s)->p) \ + ? ( (s)->x[(s)->p++] = (c), 0 ) \ + : substdio_bput((s),&(c),1) \ + ) + +extern int substdio_copy(); + +#endif diff --git a/substdio=0 b/substdio=0 new file mode 100644 index 0000000..1da81e2 --- /dev/null +++ b/substdio=0 @@ -0,0 +1 @@ +substdio.3 diff --git a/substdio=l b/substdio=l new file mode 100644 index 0000000..074aa76 --- /dev/null +++ b/substdio=l @@ -0,0 +1,5 @@ +substdio.o +substdi.o +substdo.o +subfderr.o +substdio_copy.o diff --git a/substdio_copy.3 b/substdio_copy.3 new file mode 100644 index 0000000..6fc02e6 --- /dev/null +++ b/substdio_copy.3 @@ -0,0 +1,41 @@ +.TH substdio_copy 3 +.SH NAME +substdio_copy \- copy an entire input to an output +.SH SYNTAX +.B #include + +int \fBsubstdio_copy\fP(&\fIsout\fR,&\fIsin\fR); + +substdio \fIsout\fR; +.br +substdio \fIsin\fR; +.SH DESCRIPTION +.B substdio_copy +reads characters from +.I sin +until end of file, +writing each character to +.IR sout . +It then returns 0. +It does not flush +.IR sout . + +Upon a +.I sin +error, +.B substdio_copy +returns -2, +leaving +.B errno +set appropriately. + +Upon a +.I sout +error, +.B substdio_copy +returns -3, +leaving +.B errno +set appropriately. +.SH "SEE ALSO" +substdio(3) diff --git a/substdio_copy.c b/substdio_copy.c new file mode 100644 index 0000000..71cf200 --- /dev/null +++ b/substdio_copy.c @@ -0,0 +1,18 @@ +#include "substdio.h" + +int substdio_copy(ssout,ssin) +register substdio *ssout; +register substdio *ssin; +{ + register int n; + register char *x; + + for (;;) { + n = substdio_feed(ssin); + if (n < 0) return -2; + if (!n) return 0; + x = substdio_PEEK(ssin); + if (substdio_put(ssout,x,n) == -1) return -3; + substdio_SEEK(ssin,n); + } +} diff --git a/substdio_copy=0 b/substdio_copy=0 new file mode 100644 index 0000000..1af3455 --- /dev/null +++ b/substdio_copy=0 @@ -0,0 +1 @@ +substdio_copy.3 diff --git a/substdio_in.3 b/substdio_in.3 new file mode 100644 index 0000000..f81d7a8 --- /dev/null +++ b/substdio_in.3 @@ -0,0 +1,140 @@ +.TH substdio_in 3 +.SH NAME +substdio_in \- substdio input routines +.SH SYNTAX +.B #include + +int \fBsubstdio_get\fP(&\fIs\fR,\fIto\fR,\fIlen\fR); + +int \fBsubstdio_bget\fP(&\fIs\fR,\fIto\fR,\fIlen\fR); + +int \fBsubstdio_feed\fP(&\fIs\fR); + +char *\fBsubstdio_peek\fP(&\fIs\fR); + +void \fBsubstdio_seek\fP(&\fIs\fR,\fIlen\fR); + +substdio \fIs\fR; +.br +char *\fIto\fR; +.br +int \fIlen\fR; +.SH DESCRIPTION +.B substdio_get +reads at most +.I len +characters from +.I s +into the character array +.IR to . +It returns the number of characters read, +0 for end of file, +or -1 for error, +setting +.B errno +appropriately. + +.B substdio_bget +has the same function as +.BR substdio_get . +The difference is what happens when there is no buffered data and +.I len +exceeds the buffer size: +.B substdio_get +tries to read +.I len +characters, whereas +.B substdio_bget +tries to read one buffer of characters. +In some cases +.B substdio_bget +will be more efficient than +.BR substdio_get . + +.B substdio_feed +makes sure that there is buffered data, +so that the next +.B substdio_get +or +.B substdio_bget +will succeed. +If the buffer is empty, +.B substdio_feed +tries to fill it; +it returns 0 for end of file, -1 for error, +or the number of buffered characters on success. +If the buffer already had data, +.B substdio_feed +leaves it alone and returns the number of buffered characters. + +.B substdio_peek +returns a pointer to the buffered data. + +.B substdio_seek +throws away +.I len +buffered characters, +as if they had been read. +.I len +must be at least 0 and at most the amount of buffered data. + +The +.B substdio_PEEK +and +.B substdio_SEEK +macros behave the same way as +.B substdio_peek +and +.B substdio_seek +but may evaluate their arguments several times. + +The point of +.B substdio_peek +and +.B substdio_seek +is to read data without unnecessary copies. +Sample code: + +.EX + for (;;) { +.br + n = substdio_feed(s); +.br + if (n <= 0) return n; +.br + x = substdio_PEEK(s); +.br + handle(x,n); +.br + substdio_SEEK(s,n); +.br + } +.EE + +The +.B SUBSTDIO_INSIZE +macro is defined as a reasonably large input buffer size for +.BR substdio_fdbuf . +.SH "INTERNALS" +When a +.B substdio +variable +.I s +is used for input, +there is free buffer space from +.I s\fB.x +to +.I s\fB.x\fR + +.I s\fB.n\fR; +data is buffered from +.I s\fB.x\fR + +.I s\fB.n +to +.I s\fB.x\fR + +.I s\fB.n\fR + +.I s\fB.p\fR; +the total buffer length is +.I s\fB.n\fR + +.I s\fB.p\fR. +.SH "SEE ALSO" +substdio(3) diff --git a/substdio_in=0 b/substdio_in=0 new file mode 100644 index 0000000..93b4f71 --- /dev/null +++ b/substdio_in=0 @@ -0,0 +1 @@ +substdio_in.3 diff --git a/substdio_out.3 b/substdio_out.3 new file mode 100644 index 0000000..9371c9d --- /dev/null +++ b/substdio_out.3 @@ -0,0 +1,99 @@ +.TH substdio_out 3 +.SH NAME +substdio_out \- substdio output routines +.SH SYNTAX +.B #include + +int \fBsubstdio_put\fP(&\fIs\fR,\fIfrom\fR,\fIlen\fR); +.br +int \fBsubstdio_puts\fP(&\fIs\fR,\fIfrom\fR); + +int \fBsubstdio_bput\fP(&\fIs\fR,\fIfrom\fR,\fIlen\fR); +.br +int \fBsubstdio_bputs\fP(&\fIs\fR,\fIfrom\fR); + +int \fBsubstdio_flush\fP(&\fIs\fR); + +int \fBsubstdio_putflush\fP(&\fIs\fR,\fIfrom\fR,\fIlen\fR); +.br +int \fBsubstdio_putsflush\fP(&\fIs\fR,\fIfrom\fR); + +substdio \fIs\fR; +.br +char *\fIfrom\fR; +.br +int \fIlen\fR; +.SH DESCRIPTION +.B substdio_put +writes +.I len +characters to +.I s +out of the character array +.IR from . +It returns 0 on success, -1 on error. + +.B substdio_bput +has the same function as +.BR substdio_put . +The difference is how the buffer is flushed +when there isn't enough room for +.I len +characters: +.B substdio_put +flushes the buffered data before copying the new data, +whereas +.B substdio_bput +fills the buffer with new data before flushing. + +.B substdio_flush +forces all data to be written from the internal buffer. +It returns 0 on success, -1 on error. + +.B substdio_putflush +is similar to +.B substdio_put +followed by +.BR substdio_flush , +but it avoids all internal copies. + +.BR substdio_puts , +.BR substdio_bputs , +and +.B substdio_putsflush +are the same as +.BR substdio_put , +.BR substdio_bput , +and +.B substdio_putflush +except that +.I from +must be a 0-terminated string of characters. +The string, not including the 0, is written. + +The +.B SUBSTDIO_OUTSIZE +macro is defined as a reasonably large output buffer size for +.BR substdio_fdbuf . +.SH "INTERNALS" +When a +.B substdio +variable +.I s +is used for output, +data is buffered from +.I s\fB.x +to +.I s\fB.x\fR + +.I s\fB.p\fR; +there is free buffer space from +to +.I s\fB.x\fR + +.I s\fB.p +to +.I s\fB.x\fR + +.I s\fB.n\fR; +the total buffer length is +.I s\fB.n\fR. +.SH "SEE ALSO" +substdio(3) diff --git a/substdio_out=0 b/substdio_out=0 new file mode 100644 index 0000000..4124e68 --- /dev/null +++ b/substdio_out=0 @@ -0,0 +1 @@ +substdio_out.3 diff --git a/substdo.c b/substdo.c new file mode 100644 index 0000000..fb616f7 --- /dev/null +++ b/substdo.c @@ -0,0 +1,108 @@ +#include "substdio.h" +#include "str.h" +#include "byte.h" +#include "error.h" + +static int allwrite(op,fd,buf,len) +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +int substdio_flush(s) +register substdio *s; +{ + register int p; + + p = s->p; + if (!p) return 0; + s->p = 0; + return allwrite(s->op,s->fd,s->x,p); +} + +int substdio_bput(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int n; + + while (len > (n = s->n - s->p)) { + byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n; + if (substdio_flush(s) == -1) return -1; + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int substdio_put(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int n; + + n = s->n; + if (len > n - s->p) { + if (substdio_flush(s) == -1) return -1; + /* now s->p == 0 */ + if (n < SUBSTDIO_OUTSIZE) n = SUBSTDIO_OUTSIZE; + while (len > s->n) { + if (n > len) n = len; + if (allwrite(s->op,s->fd,buf,n) == -1) return -1; + buf += n; + len -= n; + } + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int substdio_putflush(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + if (substdio_flush(s) == -1) return -1; + return allwrite(s->op,s->fd,buf,len); +} + +int substdio_bputs(s,buf) +register substdio *s; +register char *buf; +{ + return substdio_bput(s,buf,str_len(buf)); +} + +int substdio_puts(s,buf) +register substdio *s; +register char *buf; +{ + return substdio_put(s,buf,str_len(buf)); +} + +int substdio_putsflush(s,buf) +register substdio *s; +register char *buf; +{ + return substdio_putflush(s,buf,str_len(buf)); +} diff --git a/surf.3 b/surf.3 new file mode 100644 index 0000000..ba8a520 --- /dev/null +++ b/surf.3 @@ -0,0 +1,23 @@ +.TH surf 3 +.SH NAME +surf \- Simple Unpredictable Random Function +.SH SYNTAX +.B #include + +void \fBsurf\fP(\fIout\fR,\fIin\fR,\fIseed\fR); + +uint32 \fIout\fR[8]; +.br +uint32 \fIin\fR[12]; +.br +uint32 \fIseed\fR[32]; +.SH DESCRIPTION +.B surf +changes a 384-bit input to a 256-bit output, +under control of a 1024-bit seed. +When the seed is secret, +.B surf +appears to be indistinguishable from a completely random +384-bit-to-256-bit function. +.SH "SEE ALSO" +surfpcs(3) diff --git a/surf.c b/surf.c new file mode 100644 index 0000000..c4a17d0 --- /dev/null +++ b/surf.c @@ -0,0 +1,27 @@ +/* 19970320, overlap allowed 19970406 */ + +#include "surf.h" +#include "uint32.h" + +#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b)); + +void surf(out,in,seed) +uint32 out[8]; uint32 in[12]; uint32 seed[32]; +{ + uint32 t[12]; uint32 x; uint32 sum = 0; + int r; int i; int loop; + + for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i]; + for (i = 0;i < 8;++i) out[i] = seed[24 + i]; + x = t[11]; + for (loop = 0;loop < 2;++loop) { + for (r = 0;r < 16;++r) { + sum += 0x9e3779b9; + MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13) + MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13) + MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13) + } + for (i = 0;i < 8;++i) out[i] ^= t[i + 4]; + } +} diff --git a/surf.h b/surf.h new file mode 100644 index 0000000..523f528 --- /dev/null +++ b/surf.h @@ -0,0 +1,6 @@ +#ifndef SURF_H +#define SURF_H + +extern void surf(); + +#endif diff --git a/surf=0 b/surf=0 new file mode 100644 index 0000000..4a4f676 --- /dev/null +++ b/surf=0 @@ -0,0 +1 @@ +surf.3 diff --git a/surf=l b/surf=l new file mode 100644 index 0000000..84b5dc8 --- /dev/null +++ b/surf=l @@ -0,0 +1,2 @@ +surf.o +surfpcs.o diff --git a/surfpcs.3 b/surfpcs.3 new file mode 100644 index 0000000..8bd0e11 --- /dev/null +++ b/surfpcs.3 @@ -0,0 +1,69 @@ +.TH surfpcs 3 +.SH NAME +surfpcs \- SURF protected counter sums +.SH SYNTAX +.B #include + +void \fBsurfpcs_init\fP(&\fIs\fR,\fIseed\fR); + +void \fBsurfpcs_add\fP(&\fIs\fR,\fIbuf\fR,\fIlen\fR); + +void \fBsurfpcs_out\fP(&\fIs\fR,\fIh\fR); + +surfpcs \fIs\fR; +.br +uint32 \fIseed\fR[32]; +.br +unsigned char *\fIbuf\fR; +.br +unsigned int \fIlen\fR; +.br +unsigned char \fIh\fR[SURFPCS_LEN]; +.SH DESCRIPTION +.B surfpcs +converts a character string to a 256-bit output, +under control of a 1024-bit seed. +When the seed is secret, +.B surfpcs +appears to be indistinguishable from a completely random +variable-length-to-256-bit function. + +Applying +.B surfpcs +takes three steps. +First, initialize a +.B surfpcs +variable, +.IR s , +with +.BR surfpcs_init . +The seed will be recorded inside +.IR s . + +Second, feed the input to +.BR surfpcs_add . +.I buf +is a pointer to +.I len +characters of input. +You can split the input across any number of +.B surfpcs_add +calls. + +Third, call +.BR surfpcs_out . +The output will be placed into +.IR h , +an array of +.B SURFPCS_LEN +bytes. +.B SURFPCS_LEN +is 32. + +To apply +.B surfpcs +to another input you must call +.B surfpcs_init +again. +.SH "SEE ALSO" +surf(3) diff --git a/surfpcs.c b/surfpcs.c new file mode 100644 index 0000000..92c3243 --- /dev/null +++ b/surfpcs.c @@ -0,0 +1,58 @@ +/* XXX: this needs testing */ + +#include "surf.h" +#include "surfpcs.h" + +void surfpcs_init(s,k) +surfpcs *s; +uint32 k[32]; +{ + int i; + for (i = 0;i < 32;++i) s->seed[i] = k[i]; + for (i = 0;i < 8;++i) s->sum[i] = 0; + for (i = 0;i < 12;++i) s->in[i] = 0; + s->todo = 0; +} + +static uint32 littleendian[8] = { + 50462976, 117835012, 185207048, 252579084, + 319951120, 387323156, 454695192, 522067228 +} ; +#define end ((unsigned char *) &littleendian) + +#define data ((unsigned char *) s->in) +#define outdata ((unsigned char *) s->out) + +void surfpcs_add(s,x,n) +surfpcs *s; +unsigned char *x; +unsigned int n; +{ + int i; + while (n--) { + data[end[s->todo++]] = *x++; + if (s->todo == 32) { + s->todo = 0; + if (!++s->in[8]) + if (!++s->in[9]) + if (!++s->in[10]) + ++s->in[11]; + surf(s->out,s->in,s->seed); + for (i = 0;i < 8;++i) + s->sum[i] += s->out[i]; + } + } +} + +void surfpcs_out(s,h) +surfpcs *s; +unsigned char h[32]; +{ + int i; + surfpcs_add(s,".",1); + while (s->todo) surfpcs_add(s,"",1); + for (i = 0;i < 8;++i) s->in[i] = s->sum[i]; + for (;i < 12;++i) s->in[i] = 0; + surf(s->out,s->in,s->seed); + for (i = 0;i < 32;++i) h[i] = outdata[end[i]]; +} diff --git a/surfpcs.h b/surfpcs.h new file mode 100644 index 0000000..6e1b60a --- /dev/null +++ b/surfpcs.h @@ -0,0 +1,20 @@ +#ifndef SURFPCS_H +#define SURFPCS_H + +#include "uint32.h" + +typedef struct { + uint32 seed[32]; + uint32 sum[8]; + uint32 out[8]; + uint32 in[12]; + int todo; +} surfpcs; + +#define SURFPCS_LEN 32 + +extern void surfpcs_init(); +extern void surfpcs_add(); +extern void surfpcs_out(); + +#endif diff --git a/surfpcs=0 b/surfpcs=0 new file mode 100644 index 0000000..ad052cc --- /dev/null +++ b/surfpcs=0 @@ -0,0 +1 @@ +surfpcs.3 diff --git a/targets.do b/targets.do new file mode 100644 index 0000000..38d1e7d --- /dev/null +++ b/targets.do @@ -0,0 +1 @@ +dependon it man install conf-bin conf-man diff --git a/trycpp.c b/trycpp.c new file mode 100644 index 0000000..d7d83ad --- /dev/null +++ b/trycpp.c @@ -0,0 +1,7 @@ +void main() +{ +#ifdef NeXT + printf("nextstep\n"); exit(0); +#endif + printf("unknown\n"); exit(0); +} diff --git a/trydrent.c b/trydrent.c new file mode 100644 index 0000000..c778176 --- /dev/null +++ b/trydrent.c @@ -0,0 +1,8 @@ +#include +#include + +void foo() +{ + DIR *dir; + struct dirent *d; +} diff --git a/tryflock.c b/tryflock.c new file mode 100644 index 0000000..8c8aa76 --- /dev/null +++ b/tryflock.c @@ -0,0 +1,8 @@ +#include +#include +#include + +void main() +{ + flock(0,LOCK_EX | LOCK_UN | LOCK_NB); +} diff --git a/trysgact.c b/trysgact.c new file mode 100644 index 0000000..263cb21 --- /dev/null +++ b/trysgact.c @@ -0,0 +1,10 @@ +#include + +void main() +{ + struct sigaction sa; + sa.sa_handler = 0; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(0,&sa,(struct sigaction *) 0); +} diff --git a/tryulong32.c b/tryulong32.c new file mode 100644 index 0000000..a108076 --- /dev/null +++ b/tryulong32.c @@ -0,0 +1,11 @@ +void main() +{ + unsigned long u; + u = 1; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + if (!u) _exit(0); + _exit(1); +} diff --git a/tryvfork.c b/tryvfork.c new file mode 100644 index 0000000..21387e4 --- /dev/null +++ b/tryvfork.c @@ -0,0 +1,4 @@ +void main() +{ + vfork(); +} diff --git a/trywaitp.c b/trywaitp.c new file mode 100644 index 0000000..7e73bfa --- /dev/null +++ b/trywaitp.c @@ -0,0 +1,7 @@ +#include +#include + +void main() +{ + waitpid(0,0,0); +} diff --git a/uint32.h.do b/uint32.h.do new file mode 100644 index 0000000..b87401d --- /dev/null +++ b/uint32.h.do @@ -0,0 +1,7 @@ +dependon tryulong32.c compile load uint32.h1 uint32.h2 +( ./compile tryulong32.c && ./load tryulong32 && ./tryulong32 ) >/dev/null 2>&1 \ +&& cat uint32.h2 || cat uint32.h1 +rm -f tryulong32.o tryulong32 +formake '( ( ./compile tryulong32.c && ./load tryulong32 && ./tryulong32 ) >/dev/null 2>&1 \' +formake '&& cat uint32.h2 || cat uint32.h1 ) > uint32.h' +formake 'rm -f tryulong32.o tryulong32' diff --git a/uint32.h1 b/uint32.h1 new file mode 100644 index 0000000..6599aa0 --- /dev/null +++ b/uint32.h1 @@ -0,0 +1,6 @@ +#ifndef UINT32_H +#define UINT32_H + +typedef unsigned int uint32; + +#endif diff --git a/uint32.h2 b/uint32.h2 new file mode 100644 index 0000000..716430d --- /dev/null +++ b/uint32.h2 @@ -0,0 +1,6 @@ +#ifndef UINT32_H +#define UINT32_H + +typedef unsigned long uint32; + +#endif diff --git a/wait.3 b/wait.3 new file mode 100644 index 0000000..8c41f4b --- /dev/null +++ b/wait.3 @@ -0,0 +1,93 @@ +.TH wait 3 +.SH NAME +wait \- check child process status +.SH SYNTAX +.B #include + +int \fBwait_nohang\fP(&\fIwstat\fR); +.br +int \fBwait_stop\fP(&\fIwstat\fR); +.br +int \fBwait_stopnohang\fP(&\fIwstat\fR); +.br +int \fBwait_pid\fP(&\fIwstat\fR,\fIpid\fR); + +int \fBwait_exitcode\fP(\fIwstat\fR); +.br +int \fBwait_crashed\fP(\fIwstat\fR); +.br +int \fBwait_stopped\fP(\fIwstat\fR); +.br +int \fBwait_stopsig\fP(\fIwstat\fR); + +int \fIpid\fR; +.br +int \fIwstat\fR; +.SH DESCRIPTION +.B wait_nohang +looks for zombies (child processes that have exited). +If it sees a zombie, +it eliminates the zombie, +puts the zombie's exit status into +.IR wstat , +and returns the zombie's process ID. +If there are several zombies, +.B wait_nohang +picks one. +If there are children but no zombies, +.B wait_nohang +returns 0. +If there are no children, +.B wait_nohang +returns -1, +setting +.B errno +appropriately. + +.B wait_stopnohang +is similar to +.BR wait_nohang , +but it also looks for children that have stopped. + +.B wait_stop +is similar to +.BR wait_stopnohang , +but if there are children it will pause waiting for one of them +to stop or exit. + +.B wait_pid +waits for child process +.I pid +to exit. +It eliminates any zombie that shows up in the meantime, +discarding the exit status. + +.B wait_stop +and +.B wait_pid +retry upon +.BR error_intr . +.SH "STATUS PARSING" +If the child stopped, +.B wait_stopped +is nonzero; +.B wait_stopsig +is the signal that caused the child to stop. + +If the child exited by crashing, +.B wait_stopped +is zero; +.B wait_crashed +is nonzero. + +If the child exited normally, +.B wait_stopped +is zero; +.B wait_crashed +is zero; +and +.B wait_exitcode +is the child's exit code. +.SH "SEE ALSO" +wait(2), +error(3) diff --git a/wait.h b/wait.h new file mode 100644 index 0000000..cdb77c3 --- /dev/null +++ b/wait.h @@ -0,0 +1,14 @@ +#ifndef WAIT_H +#define WAIT_H + +extern int wait_pid(); +extern int wait_nohang(); +extern int wait_stop(); +extern int wait_stopnohang(); + +#define wait_crashed(w) ((w) & 127) +#define wait_exitcode(w) ((w) >> 8) +#define wait_stopsig(w) ((w) >> 8) +#define wait_stopped(w) (((w) & 127) == 127) + +#endif diff --git a/wait=0 b/wait=0 new file mode 100644 index 0000000..62a28ab --- /dev/null +++ b/wait=0 @@ -0,0 +1 @@ +wait.3 diff --git a/wait=l b/wait=l new file mode 100644 index 0000000..022ccb2 --- /dev/null +++ b/wait=l @@ -0,0 +1 @@ +wait_pid.o diff --git a/wait_pid.c b/wait_pid.c new file mode 100644 index 0000000..8dde830 --- /dev/null +++ b/wait_pid.c @@ -0,0 +1,13 @@ +#include +#include +#include "error.h" + +/* restriction: you must not care about any other child. */ +int wait_pid(wstat,pid) int *wstat; int pid; +{ + int r; + do + r = wait(wstat); + while ((r != pid) && ((r != -1) || (errno == error_intr))); + return r; +} diff --git a/warn-auto.sh b/warn-auto.sh new file mode 100644 index 0000000..36d2313 --- /dev/null +++ b/warn-auto.sh @@ -0,0 +1,2 @@ +#!/bin/sh +# WARNING: This file was auto-generated. Do not edit!