From 8d5530c492ec12fb0878d828a372ef5ee2e909f3 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Wed, 15 Feb 2006 18:27:27 +0000 Subject: [PATCH] Import fastforward 0.51 --- ALIASES | 100 ++++++++++ BLURB | 20 ++ CHANGES | 15 ++ FILES | 142 ++++++++++++++ INSTALL | 21 ++ Makefile | 593 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ README | 23 +++ SYSDEPS | 6 + TARGETS | 127 ++++++++++++ THANKS | 9 + TODO | 2 + VERSION | 1 + alloc.c | 32 +++ alloc.h | 8 + alloc_re.c | 17 ++ auto-str.c | 44 +++++ auto_qmail.h | 6 + byte.h | 13 ++ byte_chr.c | 20 ++ byte_copy.c | 14 ++ byte_cr.c | 16 ++ byte_diff.c | 16 ++ case.h | 13 ++ case_lowerb.c | 14 ++ cdb.h | 12 ++ cdb_hash.c | 16 ++ cdb_seek.c | 95 +++++++++ cdb_unpack.c | 12 ++ cdbmake.h | 35 ++++ cdbmake_add.c | 117 +++++++++++ cdbmake_hash.c | 10 + cdbmake_pack.c | 11 ++ cdbmss.c | 65 +++++++ cdbmss.h | 16 ++ coe.c | 8 + coe.h | 6 + conf-cc | 3 + conf-ld | 3 + conf-qmail | 6 + control.c | 130 +++++++++++++ control.h | 10 + env.h | 17 ++ envread.c | 30 +++ error.c | 95 +++++++++ error.h | 23 +++ error_str.c | 276 ++++++++++++++++++++++++++ exit.h | 6 + fastforward.1 | 119 ++++++++++++ fastforward.c | 408 ++++++++++++++++++++++++++++++++++++++ fd.h | 7 + fd_copy.c | 13 ++ fd_move.c | 11 ++ find-systype.sh | 144 ++++++++++++++ fmt.h | 25 +++ fmt_ulong.c | 13 ++ fork.h1 | 7 + fork.h2 | 7 + gen_alloc.h | 7 + gen_allocdefs.h | 34 ++++ getln.c | 20 ++ getln.h | 7 + getln2.c | 31 +++ hier.c | 39 ++++ install.c | 111 +++++++++++ instcheck.c | 83 ++++++++ make-compile.sh | 1 + make-load.sh | 2 + make-makelib.sh | 16 ++ newaliases.1 | 366 ++++++++++++++++++++++++++++++++++ newaliases.c | 321 ++++++++++++++++++++++++++++++ newinclude.1 | 88 +++++++++ newinclude.c | 313 ++++++++++++++++++++++++++++++ open.h | 10 + open_read.c | 6 + open_trunc.c | 6 + printforward.1 | 16 ++ printforward.c | 145 ++++++++++++++ printmaillist.1 | 15 ++ printmaillist.c | 52 +++++ qmail.c | 125 ++++++++++++ qmail.h | 24 +++ readwrite.h | 7 + scan.h | 27 +++ scan_ulong.c | 11 ++ seek.h | 15 ++ seek_set.c | 7 + setforward.1 | 204 +++++++++++++++++++ setforward.c | 174 +++++++++++++++++ setmaillist.1 | 72 +++++++ setmaillist.c | 94 +++++++++ sgetopt.c | 54 ++++++ sgetopt.h | 21 ++ sig.h | 43 ++++ sig_catch.c | 18 ++ sig_pipe.c | 5 + slurpclose.c | 19 ++ slurpclose.h | 6 + str.h | 14 ++ str_chr.c | 19 ++ str_cpy.c | 16 ++ str_diff.c | 17 ++ str_diffn.c | 18 ++ str_len.c | 15 ++ str_rchr.c | 22 +++ stralloc.h | 21 ++ stralloc_arts.c | 12 ++ stralloc_cat.c | 9 + stralloc_catb.c | 15 ++ stralloc_cats.c | 10 + stralloc_copy.c | 9 + stralloc_eady.c | 6 + stralloc_opyb.c | 14 ++ stralloc_opys.c | 10 + stralloc_pend.c | 5 + strerr.h | 80 ++++++++ strerr_die.c | 37 ++++ strerr_sys.c | 12 ++ strset.c | 130 +++++++++++++ strset.h | 29 +++ subfd.h | 15 ++ subfderr.c | 7 + subfdins.c | 13 ++ subfdouts.c | 7 + subgetopt.c | 79 ++++++++ subgetopt.h | 24 +++ substdi.c | 91 +++++++++ substdio.c | 15 ++ substdio.h | 47 +++++ substdio_copy.c | 18 ++ substdo.c | 108 +++++++++++ token822.c | 513 ++++++++++++++++++++++++++++++++++++++++++++++++ token822.h | 37 ++++ trycpp.c | 7 + trysgact.c | 10 + tryulong32.c | 11 ++ tryvfork.c | 4 + trywaitp.c | 7 + uint32.h1 | 6 + uint32.h2 | 6 + wait.h | 14 ++ wait_pid.c | 39 ++++ warn-auto.sh | 2 + 142 files changed, 7243 insertions(+) create mode 100644 ALIASES create mode 100644 BLURB create mode 100644 CHANGES create mode 100644 FILES create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 README create mode 100644 SYSDEPS create mode 100644 TARGETS create mode 100644 THANKS create mode 100644 TODO create mode 100644 VERSION create mode 100644 alloc.c create mode 100644 alloc.h create mode 100644 alloc_re.c create mode 100644 auto-str.c create mode 100644 auto_qmail.h create mode 100644 byte.h create mode 100644 byte_chr.c create mode 100644 byte_copy.c create mode 100644 byte_cr.c create mode 100644 byte_diff.c create mode 100644 case.h create mode 100644 case_lowerb.c create mode 100644 cdb.h create mode 100644 cdb_hash.c create mode 100644 cdb_seek.c create mode 100644 cdb_unpack.c create mode 100644 cdbmake.h create mode 100644 cdbmake_add.c create mode 100644 cdbmake_hash.c create mode 100644 cdbmake_pack.c create mode 100644 cdbmss.c create mode 100644 cdbmss.h create mode 100644 coe.c create mode 100644 coe.h create mode 100644 conf-cc create mode 100644 conf-ld create mode 100644 conf-qmail create mode 100644 control.c create mode 100644 control.h create mode 100644 env.h create mode 100644 envread.c create mode 100644 error.c create mode 100644 error.h create mode 100644 error_str.c create mode 100644 exit.h create mode 100644 fastforward.1 create mode 100644 fastforward.c create mode 100644 fd.h create mode 100644 fd_copy.c create mode 100644 fd_move.c create mode 100644 find-systype.sh create mode 100644 fmt.h create mode 100644 fmt_ulong.c create mode 100644 fork.h1 create mode 100644 fork.h2 create mode 100644 gen_alloc.h create mode 100644 gen_allocdefs.h create mode 100644 getln.c create mode 100644 getln.h create mode 100644 getln2.c create mode 100644 hier.c create mode 100644 install.c create mode 100644 instcheck.c create mode 100644 make-compile.sh create mode 100644 make-load.sh create mode 100644 make-makelib.sh create mode 100644 newaliases.1 create mode 100644 newaliases.c create mode 100644 newinclude.1 create mode 100644 newinclude.c create mode 100644 open.h create mode 100644 open_read.c create mode 100644 open_trunc.c create mode 100644 printforward.1 create mode 100644 printforward.c create mode 100644 printmaillist.1 create mode 100644 printmaillist.c create mode 100644 qmail.c create mode 100644 qmail.h create mode 100644 readwrite.h create mode 100644 scan.h create mode 100644 scan_ulong.c create mode 100644 seek.h create mode 100644 seek_set.c create mode 100644 setforward.1 create mode 100644 setforward.c create mode 100644 setmaillist.1 create mode 100644 setmaillist.c create mode 100644 sgetopt.c create mode 100644 sgetopt.h create mode 100644 sig.h create mode 100644 sig_catch.c create mode 100644 sig_pipe.c create mode 100644 slurpclose.c create mode 100644 slurpclose.h create mode 100644 str.h create mode 100644 str_chr.c create mode 100644 str_cpy.c create mode 100644 str_diff.c create mode 100644 str_diffn.c create mode 100644 str_len.c create mode 100644 str_rchr.c create mode 100644 stralloc.h create mode 100644 stralloc_arts.c create mode 100644 stralloc_cat.c create mode 100644 stralloc_catb.c create mode 100644 stralloc_cats.c create mode 100644 stralloc_copy.c create mode 100644 stralloc_eady.c create mode 100644 stralloc_opyb.c create mode 100644 stralloc_opys.c create mode 100644 stralloc_pend.c create mode 100644 strerr.h create mode 100644 strerr_die.c create mode 100644 strerr_sys.c create mode 100644 strset.c create mode 100644 strset.h create mode 100644 subfd.h create mode 100644 subfderr.c create mode 100644 subfdins.c create mode 100644 subfdouts.c create mode 100644 subgetopt.c create mode 100644 subgetopt.h create mode 100644 substdi.c create mode 100644 substdio.c create mode 100644 substdio.h create mode 100644 substdio_copy.c create mode 100644 substdo.c create mode 100644 token822.c create mode 100644 token822.h create mode 100644 trycpp.c create mode 100644 trysgact.c create mode 100644 tryulong32.c create mode 100644 tryvfork.c create mode 100644 trywaitp.c create mode 100644 uint32.h1 create mode 100644 uint32.h2 create mode 100644 wait.h create mode 100644 wait_pid.c create mode 100644 warn-auto.sh diff --git a/ALIASES b/ALIASES new file mode 100644 index 0000000..5775487 --- /dev/null +++ b/ALIASES @@ -0,0 +1,100 @@ +--- Setting up /etc/aliases + +Create /etc/aliases if it does not already exist. You should include +forwarding instructions for mailer-daemon, postmaster, and root: + + root: alias + postmaster: alias + mailer-daemon: alias + +Note that qmail never delivers mail to root. The instructions shown here +will deliver messages to the mailbox of the ``alias'' user. + +For further details on the format of /etc/aliases, and a list of +sendmail compatibility warnings, see the newaliases man page. + + +--- Compiling /etc/aliases + +Once /etc/aliases is ready, run newaliases to compile /etc/aliases into +/etc/aliases.cdb: + + # newaliases + +Review /etc/aliases.cdb to make sure it has the instructions you want: + + % printforward < /etc/aliases.cdb | more + +For the format of printforward's output, see the setforward man page. + +If you change /etc/aliases you will have to run newaliases again. You +may want to add a comment at the top of /etc/aliases as a reminder. + + +--- Compiling :include: files + +If you have an :include: file, say /etc/staff-list, compile it into +/etc/staff-list.bin: + + # newinclude /etc/staff-list + +See the newinclude man page for a list of sendmail compatibility +warnings. Review /etc/staff-list.bin: + + % printmaillist < /etc/staff-list.bin | more + +For the format of printmaillist's output, see the setmaillist man page. + +If you change /etc/staff-list you will have to run newinclude again. You +may want to add a comment at the top of /etc/staff-list as a reminder. + + +--- Configuring qmail to use /etc/aliases + +To activate /etc/aliases, put this line into ~alias/.qmail-default: + + | fastforward -d /etc/aliases.cdb + +If qmail is already running, make sure to chmod +t ~alias before you +edit .qmail files in ~alias, and chmod -t ~alias after. + + +--- Testing aliases + +To check the expansion of postmaster@your.host without sending any mail: + + % env DEFAULT=postmaster HOST=your.host fastforward -nd /etc/aliases.cdb + +Replace your.host with your fully qualified domain name. Make sure to +include the -nd. + +Next, try sending a message to postmaster@your.host. Watch the qmail log +and the final mailbox to make sure the alias works the way you want. + +You can check other aliases the same way. + + +--- Using /etc/aliases for virtual domains + +To put all addresses at virt.dom under control of /etc/aliases, add + + virt.dom:alias + +to /var/qmail/control/virtualdomains, and give qmail-send a HUP signal. +Also add + + virt.dom + +to /var/qmail/control/rcpthosts so that qmail accepts mail for virt.dom +from remote hosts. Now you can handle virt.dom in /etc/aliases: + + billing@virt.dom: joe, fred + (this line catches all other addresses)@virt.dom: joe + +Note that postmaster@virt.dom will go to joe; the @virt.dom instruction +overrides the postmaster instruction. Note, however, that other .qmail +files in ~alias override ~alias/.qmail-default, so you can set up +~alias/.qmail-postmaster to handle postmaster@everything. + +Beware that sendmail does not support domain-specific instructions in +/etc/aliases; they are a fastforward feature. diff --git a/BLURB b/BLURB new file mode 100644 index 0000000..9604f46 --- /dev/null +++ b/BLURB @@ -0,0 +1,20 @@ +fastforward handles qmail forwarding according to a cdb database. It can +create forwarding databases from a sendmail-style /etc/aliases or from +user-oriented virtual-domain tables. + +fastforward supports external mailing lists, stored in a binary format +for fast access. It has a tool to convert sendmail-style include files +into binary lists. + +fastforward is more reliable than sendmail. sendmail can't deal with +long aliases, or deeply nested aliases, or deeply nested include files; +fastforward has no limits other than memory. sendmail can produce +corrupted alias files if the system crashes; fastforward is crashproof. + +fastforward's database-building tools are much faster than sendmail's +newaliases. Even better, fastforward deliveries don't pause while the +database is being rebuilt. + +fastforward does not support insecure sendmail-style program deliveries +from include files; you can use qmail's secure built-in mechanisms +instead. fastforward does support program deliveries from /etc/aliases. diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..813ba6f --- /dev/null +++ b/CHANGES @@ -0,0 +1,15 @@ +19980519 version: fastforward 0.51, alpha. +19980519 code: added preline variant in fastforward; updated setforward, + printforward, newaliases accordingly. +19980519 doc: added virtual-domains section to ALIASES. +19980519 doc: used -d in ALIASES. +19980519 code: added fastforward -d. +19980519 doc: put version and home page into fastforward.1. +19980519 doc: simplified INSTALL. +19980519 doc: added ALIASES. +19980519 doc: expanded explanation in conf-qmail. +19980519 code: switched to new install. +19980420 portability problem: IRIX doesn't have vfork(). impact: + couldn't compile under IRIX. fix: include fork.h in + fastforward.c. tnx JB. +19980420 fastforward 0.50, alpha. diff --git a/FILES b/FILES new file mode 100644 index 0000000..2f00b77 --- /dev/null +++ b/FILES @@ -0,0 +1,142 @@ +BLURB +README +TODO +THANKS +CHANGES +FILES +TARGETS +VERSION +SYSDEPS +Makefile +ALIASES +INSTALL +hier.c +fastforward.1 +fastforward.c +printforward.1 +printforward.c +setforward.1 +setforward.c +printmaillist.1 +printmaillist.c +setmaillist.1 +setmaillist.c +newaliases.1 +newaliases.c +newinclude.1 +newinclude.c +auto-str.c +install.c +instcheck.c +conf-cc +conf-ld +find-systype.sh +make-compile.sh +make-load.sh +make-makelib.sh +trycpp.c +warn-auto.sh +alloc.h +alloc.c +alloc_re.c +case.h +case_lowerb.c +cdb.h +cdb_hash.c +cdb_seek.c +cdb_unpack.c +cdbmake.h +cdbmake_add.c +cdbmake_hash.c +cdbmake_pack.c +cdbmss.h +cdbmss.c +control.h +control.c +env.h +envread.c +error.h +error.c +error_str.c +fd.h +fd_copy.c +fd_move.c +fork.h1 +fork.h2 +tryvfork.c +fmt.h +fmt_ulong.c +scan.h +scan_ulong.c +getln.h +getln.c +getln2.c +sgetopt.h +sgetopt.c +subgetopt.h +subgetopt.c +open.h +open_read.c +open_trunc.c +conf-qmail +auto_qmail.h +qmail.h +qmail.c +seek.h +seek_set.c +sig.h +sig_catch.c +sig_pipe.c +trysgact.c +byte.h +byte_chr.c +byte_copy.c +byte_cr.c +byte_diff.c +str.h +str_chr.c +str_cpy.c +str_diff.c +str_diffn.c +str_len.c +str_rchr.c +gen_alloc.h +gen_allocdefs.h +stralloc.h +stralloc_eady.c +stralloc_pend.c +stralloc_copy.c +stralloc_opyb.c +stralloc_opys.c +stralloc_cat.c +stralloc_catb.c +stralloc_cats.c +stralloc_arts.c +strset.h +strset.c +substdio.h +substdio.c +substdi.c +substdo.c +substdio_copy.c +subfd.h +subfderr.c +subfdouts.c +subfdins.c +readwrite.h +exit.h +token822.h +token822.c +uint32.h1 +uint32.h2 +tryulong32.c +wait.h +wait_pid.c +trywaitp.c +strerr.h +strerr_sys.c +strerr_die.c +slurpclose.h +slurpclose.c +coe.h +coe.c diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..7e564f4 --- /dev/null +++ b/INSTALL @@ -0,0 +1,21 @@ +Like any other piece of software (and information generally), +fastforward comes with NO WARRANTY. + + +Things you have to decide before starting: + +* Where qmail is installed, normally /var/qmail. (To change this +directory, edit conf-qmail now.) + + +How to install: + + 1. Create and install the programs and man pages: + # make setup check + + 2. To configure qmail to use /etc/aliases, see ALIASES. + + +That's it! To report success: + % ( echo 'First M. Last'; cat `cat SYSDEPS` ) | mail djb-qst@cr.yp.to +Replace First M. Last with your name. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c16d93c --- /dev/null +++ b/Makefile @@ -0,0 +1,593 @@ +# Don't edit Makefile! Use conf-* for configuration. + +SHELL=/bin/sh + +default: it + +alloc.a: \ +makelib alloc.o alloc_re.o + ./makelib alloc.a alloc.o alloc_re.o + +alloc.o: \ +compile alloc.c alloc.h error.h + ./compile alloc.c + +alloc_re.o: \ +compile alloc_re.c alloc.h byte.h + ./compile alloc_re.c + +auto-ccld.sh: \ +conf-cc conf-ld warn-auto.sh + ( cat warn-auto.sh; \ + echo CC=\'`head -1 conf-cc`\'; \ + echo LD=\'`head -1 conf-ld`\' \ + ) > auto-ccld.sh + +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 readwrite.h exit.h + ./compile auto-str.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 + ./compile byte_chr.c + +byte_copy.o: \ +compile byte_copy.c byte.h + ./compile byte_copy.c + +byte_cr.o: \ +compile byte_cr.c byte.h + ./compile byte_cr.c + +byte_diff.o: \ +compile byte_diff.c byte.h + ./compile byte_diff.c + +case.a: \ +makelib case_lowerb.o + ./makelib case.a case_lowerb.o + +case_lowerb.o: \ +compile case_lowerb.c case.h + ./compile case_lowerb.c + +cdb.a: \ +makelib cdb_hash.o cdb_unpack.o cdb_seek.o + ./makelib cdb.a cdb_hash.o cdb_unpack.o cdb_seek.o + +cdb_hash.o: \ +compile cdb_hash.c cdb.h uint32.h + ./compile cdb_hash.c + +cdb_seek.o: \ +compile cdb_seek.c cdb.h uint32.h + ./compile cdb_seek.c + +cdb_unpack.o: \ +compile cdb_unpack.c cdb.h uint32.h + ./compile cdb_unpack.c + +cdbmake.a: \ +makelib cdbmake_pack.o cdbmake_hash.o cdbmake_add.o + ./makelib cdbmake.a cdbmake_pack.o cdbmake_hash.o \ + cdbmake_add.o + +cdbmake_add.o: \ +compile cdbmake_add.c cdbmake.h uint32.h + ./compile cdbmake_add.c + +cdbmake_hash.o: \ +compile cdbmake_hash.c cdbmake.h uint32.h + ./compile cdbmake_hash.c + +cdbmake_pack.o: \ +compile cdbmake_pack.c cdbmake.h uint32.h + ./compile cdbmake_pack.c + +cdbmss.o: \ +compile cdbmss.c readwrite.h seek.h alloc.h cdbmss.h cdbmake.h \ +uint32.h substdio.h + ./compile cdbmss.c + +check: \ +it instcheck + ./instcheck + +coe.o: \ +compile coe.c coe.h + ./compile coe.c + +compile: \ +make-compile warn-auto.sh systype + ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \ + compile + chmod 755 compile + +control.o: \ +compile control.c readwrite.h open.h getln.h stralloc.h gen_alloc.h \ +substdio.h error.h control.h alloc.h scan.h + ./compile control.c + +env.a: \ +makelib envread.o + ./makelib env.a envread.o + +envread.o: \ +compile envread.c env.h str.h + ./compile envread.c + +error.a: \ +makelib error.o error_str.o + ./makelib error.a error.o error_str.o + +error.o: \ +compile error.c error.h + ./compile error.c + +error_str.o: \ +compile error_str.c error.h + ./compile error_str.c + +fastforward: \ +load fastforward.o slurpclose.o coe.o strset.o qmail.o auto_qmail.o \ +getopt.a cdb.a env.a strerr.a substdio.a stralloc.a alloc.a error.a \ +case.a str.a fs.a sig.a wait.a seek.a open.a fd.a + ./load fastforward slurpclose.o coe.o strset.o qmail.o \ + auto_qmail.o getopt.a cdb.a env.a strerr.a substdio.a \ + stralloc.a alloc.a error.a case.a str.a fs.a sig.a wait.a \ + seek.a open.a fd.a + +fastforward.0: \ +fastforward.1 + nroff -man fastforward.1 > fastforward.0 + +fastforward.o: \ +compile fastforward.c stralloc.h gen_alloc.h substdio.h subfd.h \ +substdio.h strset.h uint32.h sgetopt.h subgetopt.h readwrite.h exit.h \ +strerr.h env.h sig.h qmail.h substdio.h fmt.h case.h alloc.h coe.h \ +seek.h wait.h fork.h + ./compile fastforward.c + +fd.a: \ +makelib fd_copy.o fd_move.o + ./makelib fd.a fd_copy.o fd_move.o + +fd_copy.o: \ +compile fd_copy.c fd.h + ./compile fd_copy.c + +fd_move.o: \ +compile fd_move.c fd.h + ./compile fd_move.c + +find-systype: \ +find-systype.sh auto-ccld.sh + cat auto-ccld.sh find-systype.sh > find-systype + chmod 755 find-systype + +fmt_ulong.o: \ +compile fmt_ulong.c fmt.h + ./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_ulong.o scan_ulong.o + ./makelib fs.a fmt_ulong.o scan_ulong.o + +getln.a: \ +makelib getln.o getln2.o + ./makelib getln.a getln.o getln2.o + +getln.o: \ +compile getln.c substdio.h byte.h stralloc.h gen_alloc.h getln.h + ./compile getln.c + +getln2.o: \ +compile getln2.c substdio.h stralloc.h gen_alloc.h byte.h getln.h + ./compile getln2.c + +getopt.a: \ +makelib subgetopt.o sgetopt.o + ./makelib getopt.a subgetopt.o sgetopt.o + +hassgact.h: \ +trysgact.c compile load + ( ( ./compile trysgact.c && ./load trysgact ) >/dev/null \ + 2>&1 \ + && echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h + rm -f trysgact.o trysgact + +haswaitp.h: \ +trywaitp.c compile load + ( ( ./compile trywaitp.c && ./load trywaitp ) >/dev/null \ + 2>&1 \ + && echo \#define HASWAITPID 1 || exit 0 ) > haswaitp.h + rm -f trywaitp.o trywaitp + +hier.o: \ +compile hier.c auto_qmail.h + ./compile hier.c + +install: \ +load install.o hier.o auto_qmail.o strerr.a substdio.a error.a open.a \ +str.a + ./load install hier.o auto_qmail.o strerr.a substdio.a \ + error.a open.a str.a + +install.o: \ +compile install.c substdio.h strerr.h error.h open.h readwrite.h \ +exit.h + ./compile install.c + +instcheck: \ +load instcheck.o hier.o auto_qmail.o strerr.a substdio.a error.a \ +str.a + ./load instcheck hier.o auto_qmail.o strerr.a substdio.a \ + error.a str.a + +instcheck.o: \ +compile instcheck.c strerr.h error.h readwrite.h exit.h + ./compile instcheck.c + +it: \ +prog man + +load: \ +make-load warn-auto.sh systype + ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load + chmod 755 load + +make-compile: \ +make-compile.sh auto-ccld.sh + cat auto-ccld.sh make-compile.sh > make-compile + chmod 755 make-compile + +make-load: \ +make-load.sh auto-ccld.sh + cat auto-ccld.sh make-load.sh > make-load + chmod 755 make-load + +make-makelib: \ +make-makelib.sh auto-ccld.sh + cat auto-ccld.sh make-makelib.sh > make-makelib + chmod 755 make-makelib + +makelib: \ +make-makelib warn-auto.sh systype + ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \ + makelib + chmod 755 makelib + +man: \ +fastforward.0 printforward.0 setforward.0 newaliases.0 \ +printmaillist.0 setmaillist.0 newinclude.0 + +newaliases: \ +load newaliases.o auto_qmail.o token822.o control.o cdbmss.o \ +cdbmake.a strerr.a getln.a substdio.a stralloc.a alloc.a error.a \ +str.a fs.a seek.a open.a case.a + ./load newaliases auto_qmail.o token822.o control.o \ + cdbmss.o cdbmake.a strerr.a getln.a substdio.a stralloc.a \ + alloc.a error.a str.a fs.a seek.a open.a case.a + +newaliases.0: \ +newaliases.1 + nroff -man newaliases.1 > newaliases.0 + +newaliases.o: \ +compile newaliases.c substdio.h strerr.h stralloc.h gen_alloc.h \ +getln.h open.h readwrite.h token822.h gen_alloc.h control.h \ +auto_qmail.h case.h cdbmss.h cdbmake.h uint32.h substdio.h + ./compile newaliases.c + +newinclude: \ +load newinclude.o auto_qmail.o token822.o control.o getln.a strerr.a \ +stralloc.a env.a alloc.a substdio.a error.a str.a fs.a open.a wait.a \ +fd.a + ./load newinclude auto_qmail.o token822.o control.o \ + getln.a strerr.a stralloc.a env.a alloc.a substdio.a \ + error.a str.a fs.a open.a wait.a fd.a + +newinclude.0: \ +newinclude.1 + nroff -man newinclude.1 > newinclude.0 + +newinclude.o: \ +compile newinclude.c substdio.h strerr.h stralloc.h gen_alloc.h \ +getln.h open.h readwrite.h token822.h gen_alloc.h control.h \ +auto_qmail.h env.h + ./compile newinclude.c + +open.a: \ +makelib open_read.o open_trunc.o + ./makelib open.a open_read.o open_trunc.o + +open_read.o: \ +compile open_read.c open.h + ./compile open_read.c + +open_trunc.o: \ +compile open_trunc.c open.h + ./compile open_trunc.c + +printforward: \ +load printforward.o cdb.a strerr.a substdio.a stralloc.a alloc.a \ +error.a str.a + ./load printforward cdb.a strerr.a substdio.a stralloc.a \ + alloc.a error.a str.a + +printforward.0: \ +printforward.1 + nroff -man printforward.1 > printforward.0 + +printforward.o: \ +compile printforward.c substdio.h subfd.h substdio.h strerr.h \ +stralloc.h gen_alloc.h cdb.h uint32.h + ./compile printforward.c + +printmaillist: \ +load printmaillist.o getln.a strerr.a substdio.a stralloc.a alloc.a \ +error.a str.a + ./load printmaillist getln.a strerr.a substdio.a \ + stralloc.a alloc.a error.a str.a + +printmaillist.0: \ +printmaillist.1 + nroff -man printmaillist.1 > printmaillist.0 + +printmaillist.o: \ +compile printmaillist.c substdio.h subfd.h substdio.h strerr.h \ +stralloc.h gen_alloc.h getln.h + ./compile printmaillist.c + +prog: \ +fastforward printforward setforward newaliases printmaillist \ +setmaillist newinclude + +qmail.o: \ +compile qmail.c substdio.h readwrite.h wait.h exit.h fork.h fd.h \ +qmail.h substdio.h auto_qmail.h + ./compile qmail.c + +scan_ulong.o: \ +compile scan_ulong.c scan.h + ./compile scan_ulong.c + +seek.a: \ +makelib seek_set.o + ./makelib seek.a seek_set.o + +seek_set.o: \ +compile seek_set.c seek.h + ./compile seek_set.c + +setforward: \ +load setforward.o cdbmss.o cdbmake.a strerr.a substdio.a stralloc.a \ +alloc.a error.a str.a seek.a open.a case.a + ./load setforward cdbmss.o cdbmake.a strerr.a substdio.a \ + stralloc.a alloc.a error.a str.a seek.a open.a case.a + +setforward.0: \ +setforward.1 + nroff -man setforward.1 > setforward.0 + +setforward.o: \ +compile setforward.c substdio.h subfd.h substdio.h strerr.h \ +stralloc.h gen_alloc.h open.h case.h readwrite.h cdbmss.h cdbmake.h \ +uint32.h substdio.h + ./compile setforward.c + +setmaillist: \ +load setmaillist.o getln.a strerr.a substdio.a stralloc.a alloc.a \ +error.a str.a open.a + ./load setmaillist getln.a strerr.a substdio.a stralloc.a \ + alloc.a error.a str.a open.a + +setmaillist.0: \ +setmaillist.1 + nroff -man setmaillist.1 > setmaillist.0 + +setmaillist.o: \ +compile setmaillist.c substdio.h subfd.h substdio.h strerr.h \ +stralloc.h gen_alloc.h getln.h open.h readwrite.h + ./compile setmaillist.c + +setup: \ +it install + ./install + +sgetopt.o: \ +compile sgetopt.c substdio.h subfd.h substdio.h sgetopt.h subgetopt.h \ +subgetopt.h + ./compile sgetopt.c + +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.h hassgact.h + ./compile sig_catch.c + +sig_pipe.o: \ +compile sig_pipe.c sig.h + ./compile sig_pipe.c + +slurpclose.o: \ +compile slurpclose.c stralloc.h gen_alloc.h readwrite.h slurpclose.h \ +error.h + ./compile slurpclose.c + +str.a: \ +makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.o \ +str_rchr.o byte_chr.o byte_diff.o byte_copy.o byte_cr.o + ./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \ + str_chr.o str_rchr.o byte_chr.o byte_diff.o byte_copy.o \ + byte_cr.o + +str_chr.o: \ +compile str_chr.c str.h + ./compile str_chr.c + +str_cpy.o: \ +compile str_cpy.c str.h + ./compile str_cpy.c + +str_diff.o: \ +compile str_diff.c str.h + ./compile str_diff.c + +str_diffn.o: \ +compile str_diffn.c str.h + ./compile str_diffn.c + +str_len.o: \ +compile str_len.c str.h + ./compile str_len.c + +str_rchr.o: \ +compile str_rchr.c str.h + ./compile str_rchr.c + +stralloc.a: \ +makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \ +stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \ +stralloc_catb.o 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 str.h stralloc.h gen_alloc.h + ./compile stralloc_arts.c + +stralloc_cat.o: \ +compile stralloc_cat.c byte.h stralloc.h gen_alloc.h + ./compile stralloc_cat.c + +stralloc_catb.o: \ +compile stralloc_catb.c stralloc.h gen_alloc.h byte.h + ./compile stralloc_catb.c + +stralloc_cats.o: \ +compile stralloc_cats.c byte.h str.h stralloc.h gen_alloc.h + ./compile stralloc_cats.c + +stralloc_copy.o: \ +compile stralloc_copy.c byte.h stralloc.h gen_alloc.h + ./compile stralloc_copy.c + +stralloc_eady.o: \ +compile stralloc_eady.c alloc.h stralloc.h gen_alloc.h \ +gen_allocdefs.h + ./compile stralloc_eady.c + +stralloc_opyb.o: \ +compile stralloc_opyb.c stralloc.h gen_alloc.h byte.h + ./compile stralloc_opyb.c + +stralloc_opys.o: \ +compile stralloc_opys.c byte.h str.h stralloc.h gen_alloc.h + ./compile stralloc_opys.c + +stralloc_pend.o: \ +compile stralloc_pend.c alloc.h stralloc.h gen_alloc.h \ +gen_allocdefs.h + ./compile stralloc_pend.c + +strerr.a: \ +makelib strerr_sys.o strerr_die.o + ./makelib strerr.a strerr_sys.o strerr_die.o + +strerr_die.o: \ +compile strerr_die.c substdio.h subfd.h substdio.h exit.h strerr.h + ./compile strerr_die.c + +strerr_sys.o: \ +compile strerr_sys.c error.h strerr.h + ./compile strerr_sys.c + +strset.o: \ +compile strset.c strset.h uint32.h str.h byte.h + ./compile strset.c + +subfderr.o: \ +compile subfderr.c readwrite.h substdio.h subfd.h substdio.h + ./compile subfderr.c + +subfdins.o: \ +compile subfdins.c readwrite.h substdio.h subfd.h substdio.h + ./compile subfdins.c + +subfdouts.o: \ +compile subfdouts.c readwrite.h substdio.h subfd.h substdio.h + ./compile subfdouts.c + +subgetopt.o: \ +compile subgetopt.c subgetopt.h + ./compile subgetopt.c + +substdi.o: \ +compile substdi.c substdio.h byte.h error.h + ./compile substdi.c + +substdio.a: \ +makelib substdio.o substdi.o substdo.o subfderr.o subfdouts.o \ +subfdins.o substdio_copy.o + ./makelib substdio.a substdio.o substdi.o substdo.o \ + subfderr.o subfdouts.o subfdins.o substdio_copy.o + +substdio.o: \ +compile substdio.c substdio.h + ./compile substdio.c + +substdio_copy.o: \ +compile substdio_copy.c substdio.h + ./compile substdio_copy.c + +substdo.o: \ +compile substdo.c substdio.h str.h byte.h error.h + ./compile substdo.c + +systype: \ +find-systype trycpp.c + ./find-systype > systype + +token822.o: \ +compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \ +gen_alloc.h gen_allocdefs.h + ./compile token822.c + +uint32.h: \ +tryulong32.c compile load uint32.h1 uint32.h2 + ( ( ./compile tryulong32.c && ./load tryulong32 && \ + ./tryulong32 ) >/dev/null 2>&1 \ + && cat uint32.h2 || cat uint32.h1 ) > uint32.h + rm -f tryulong32.o tryulong32 + +wait.a: \ +makelib wait_pid.o + ./makelib wait.a wait_pid.o + +wait_pid.o: \ +compile wait_pid.c error.h haswaitp.h + ./compile wait_pid.c diff --git a/README b/README new file mode 100644 index 0000000..f8da024 --- /dev/null +++ b/README @@ -0,0 +1,23 @@ +fastforward 0.51, alpha. +19980519 +Copyright 1998 +D. J. Bernstein, djb@pobox.com + +fastforward handles qmail forwarding according to a cdb database. It can +create forwarding databases from a sendmail-style /etc/aliases or from +user-oriented virtual-domain tables. See BLURB for a more detailed +advertisement. + +INSTALL says how to set up fastforward. + +You may distribute unmodified copies of the fastforward package. + +The rest of this file is a list of systypes where various versions of +fastforward have been reported to work. + +0.50: bsd.os-2.0.1-:i386-:-:pentium-:- +0.50: irix-5.3-11091811-:-:-:ip19-:- (tnx JB) +0.50: linux-2.0.7-:i386-:-:i486-:- (tnx TLM) +0.50: linux-2.0.33-:i386-:-:i486-:- (tnx TB) +0.50: osf1-v4.0-878-:-:-:alpha-:- (tnx BJM) +0.50: sunos-5.6-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx TWH) diff --git a/SYSDEPS b/SYSDEPS new file mode 100644 index 0000000..ba3c676 --- /dev/null +++ b/SYSDEPS @@ -0,0 +1,6 @@ +VERSION +systype +hassgact.h +haswaitp.h +fork.h +uint32.h diff --git a/TARGETS b/TARGETS new file mode 100644 index 0000000..f7824b3 --- /dev/null +++ b/TARGETS @@ -0,0 +1,127 @@ +auto-ccld.sh +make-load +find-systype +systype +load +make-compile +compile +uint32.h +fork.h +fastforward.o +slurpclose.o +coe.o +strset.o +qmail.o +auto-str.o +make-makelib +makelib +substdio.o +substdi.o +substdo.o +subfderr.o +subfdouts.o +subfdins.o +substdio_copy.o +substdio.a +error.o +error_str.o +error.a +str_len.o +str_diff.o +str_diffn.o +str_cpy.o +str_chr.o +str_rchr.o +byte_chr.o +byte_diff.o +byte_copy.o +byte_cr.o +str.a +auto-str +auto_qmail.c +auto_qmail.o +subgetopt.o +sgetopt.o +getopt.a +cdb_hash.o +cdb_unpack.o +cdb_seek.o +cdb.a +envread.o +env.a +strerr_sys.o +strerr_die.o +strerr.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.a +alloc.o +alloc_re.o +alloc.a +case_lowerb.o +case.a +fmt_ulong.o +scan_ulong.o +fs.a +hassgact.h +sig_catch.o +sig_pipe.o +sig.a +haswaitp.h +wait_pid.o +wait.a +seek_set.o +seek.a +open_read.o +open_trunc.o +open.a +fd_copy.o +fd_move.o +fd.a +fastforward +printforward.o +printforward +setforward.o +cdbmss.o +cdbmake_pack.o +cdbmake_hash.o +cdbmake_add.o +cdbmake.a +setforward +newaliases.o +token822.o +control.o +getln.o +getln2.o +getln.a +newaliases +printmaillist.o +printmaillist +setmaillist.o +setmaillist +newinclude.o +newinclude +prog +fastforward.0 +printforward.0 +setforward.0 +newaliases.0 +printmaillist.0 +setmaillist.0 +newinclude.0 +man +it +install.o +hier.o +install +setup +instcheck.o +instcheck +check diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..5bb53e7 --- /dev/null +++ b/THANKS @@ -0,0 +1,9 @@ +BJM = Barry J. Miller +JB = Jos Backus +LW = Lionel Widdifield +MS = Mikael Suokas +PJG = Paul Graham +SAC = Shawn A. Clifford +TB = Thomas Bullinger +TLM = Timothy L. Mayo +TWH = Thomas W. Holt diff --git a/TODO b/TODO new file mode 100644 index 0000000..6ad2d49 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +consider other table formats +test diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..108e0ca --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +fastforward 0.51 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_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_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/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_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/cdb.h b/cdb.h new file mode 100644 index 0000000..571e5d6 --- /dev/null +++ b/cdb.h @@ -0,0 +1,12 @@ +#ifndef CDB_H +#define CDB_H + +#include "uint32.h" + +extern uint32 cdb_hash(); +extern uint32 cdb_unpack(); + +extern int cdb_bread(); +extern int cdb_seek(); + +#endif diff --git a/cdb_hash.c b/cdb_hash.c new file mode 100644 index 0000000..8238020 --- /dev/null +++ b/cdb_hash.c @@ -0,0 +1,16 @@ +#include "cdb.h" + +uint32 cdb_hash(buf,len) +unsigned char *buf; +unsigned int len; +{ + uint32 h; + + h = 5381; + while (len) { + --len; + h += (h << 5); + h ^= (uint32) *buf++; + } + return h; +} diff --git a/cdb_seek.c b/cdb_seek.c new file mode 100644 index 0000000..87ab614 --- /dev/null +++ b/cdb_seek.c @@ -0,0 +1,95 @@ +#include +#include +extern int errno; +#include "cdb.h" + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +int cdb_bread(fd,buf,len) +int fd; +char *buf; +int len; +{ + int r; + while (len > 0) { + do + r = read(fd,buf,len); + while ((r == -1) && (errno == EINTR)); + if (r == -1) return -1; + if (r == 0) { errno = EIO; return -1; } + buf += r; + len -= r; + } + return 0; +} + +static int match(fd,key,len) +int fd; +char *key; +unsigned int len; +{ + char buf[32]; + int n; + int i; + + while (len > 0) { + n = sizeof(buf); + if (n > len) n = len; + if (cdb_bread(fd,buf,n) == -1) return -1; + for (i = 0;i < n;++i) if (buf[i] != key[i]) return 0; + key += n; + len -= n; + } + return 1; +} + +int cdb_seek(fd,key,len,dlen) +int fd; +char *key; +unsigned int len; +uint32 *dlen; +{ + char packbuf[8]; + uint32 pos; + uint32 h; + uint32 lenhash; + uint32 h2; + uint32 loop; + uint32 poskd; + + h = cdb_hash(key,len); + + pos = 8 * (h & 255); + if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1; + + if (cdb_bread(fd,packbuf,8) == -1) return -1; + + pos = cdb_unpack(packbuf); + lenhash = cdb_unpack(packbuf + 4); + + if (!lenhash) return 0; + h2 = (h >> 8) % lenhash; + + for (loop = 0;loop < lenhash;++loop) { + if (lseek(fd,(off_t) (pos + 8 * h2),SEEK_SET) == -1) return -1; + if (cdb_bread(fd,packbuf,8) == -1) return -1; + poskd = cdb_unpack(packbuf + 4); + if (!poskd) return 0; + if (cdb_unpack(packbuf) == h) { + if (lseek(fd,(off_t) poskd,SEEK_SET) == -1) return -1; + if (cdb_bread(fd,packbuf,8) == -1) return -1; + if (cdb_unpack(packbuf) == len) + switch(match(fd,key,len)) { + case -1: + return -1; + case 1: + *dlen = cdb_unpack(packbuf + 4); + return 1; + } + } + if (++h2 == lenhash) h2 = 0; + } + return 0; +} diff --git a/cdb_unpack.c b/cdb_unpack.c new file mode 100644 index 0000000..c882202 --- /dev/null +++ b/cdb_unpack.c @@ -0,0 +1,12 @@ +#include "cdb.h" + +uint32 cdb_unpack(buf) +unsigned char *buf; +{ + uint32 num; + num = buf[3]; num <<= 8; + num += buf[2]; num <<= 8; + num += buf[1]; num <<= 8; + num += buf[0]; + return num; +} diff --git a/cdbmake.h b/cdbmake.h new file mode 100644 index 0000000..883a231 --- /dev/null +++ b/cdbmake.h @@ -0,0 +1,35 @@ +#ifndef CDBMAKE_H +#define CDBMAKE_H + +#include "uint32.h" + +#define CDBMAKE_HPLIST 1000 + +struct cdbmake_hp { uint32 h; uint32 p; } ; + +struct cdbmake_hplist { + struct cdbmake_hp hp[CDBMAKE_HPLIST]; + struct cdbmake_hplist *next; + int num; +} ; + +struct cdbmake { + char final[2048]; + uint32 count[256]; + uint32 start[256]; + struct cdbmake_hplist *head; + struct cdbmake_hp *split; /* includes space for hash */ + struct cdbmake_hp *hash; + uint32 numentries; +} ; + +extern void cdbmake_pack(); +#define CDBMAKE_HASHSTART ((uint32) 5381) +extern uint32 cdbmake_hashadd(); + +extern void cdbmake_init(); +extern int cdbmake_add(); +extern int cdbmake_split(); +extern uint32 cdbmake_throw(); + +#endif diff --git a/cdbmake_add.c b/cdbmake_add.c new file mode 100644 index 0000000..115f828 --- /dev/null +++ b/cdbmake_add.c @@ -0,0 +1,117 @@ +#include "cdbmake.h" + +void cdbmake_init(cdbm) +struct cdbmake *cdbm; +{ + cdbm->head = 0; + cdbm->split = 0; + cdbm->hash = 0; + cdbm->numentries = 0; +} + +int cdbmake_add(cdbm,h,p,alloc) +struct cdbmake *cdbm; +uint32 h; +uint32 p; +char *(*alloc)(); +{ + struct cdbmake_hplist *head; + + head = cdbm->head; + if (!head || (head->num >= CDBMAKE_HPLIST)) { + head = (struct cdbmake_hplist *) alloc(sizeof(struct cdbmake_hplist)); + if (!head) return 0; + head->num = 0; + head->next = cdbm->head; + cdbm->head = head; + } + head->hp[head->num].h = h; + head->hp[head->num].p = p; + ++head->num; + ++cdbm->numentries; + return 1; +} + +int cdbmake_split(cdbm,alloc) +struct cdbmake *cdbm; +char *(*alloc)(); +{ + int i; + uint32 u; + uint32 memsize; + struct cdbmake_hplist *x; + + for (i = 0;i < 256;++i) + cdbm->count[i] = 0; + + for (x = cdbm->head;x;x = x->next) { + i = x->num; + while (i--) + ++cdbm->count[255 & x->hp[i].h]; + } + + memsize = 1; + for (i = 0;i < 256;++i) { + u = cdbm->count[i] * 2; + if (u > memsize) + memsize = u; + } + + memsize += cdbm->numentries; /* no overflow possible up to now */ + u = (uint32) 0 - (uint32) 1; + u /= sizeof(struct cdbmake_hp); + if (memsize > u) return 0; + + cdbm->split = (struct cdbmake_hp *) alloc(memsize * sizeof(struct cdbmake_hp)); + if (!cdbm->split) return 0; + + cdbm->hash = cdbm->split + cdbm->numentries; + + u = 0; + for (i = 0;i < 256;++i) { + u += cdbm->count[i]; /* bounded by numentries, so no overflow */ + cdbm->start[i] = u; + } + + for (x = cdbm->head;x;x = x->next) { + i = x->num; + while (i--) + cdbm->split[--cdbm->start[255 & x->hp[i].h]] = x->hp[i]; + } + + return 1; +} + +uint32 cdbmake_throw(cdbm,pos,b) +struct cdbmake *cdbm; +uint32 pos; +int b; +{ + uint32 len; + uint32 j; + uint32 count; + struct cdbmake_hp *hp; + uint32 where; + + count = cdbm->count[b]; + + len = count + count; /* no overflow possible */ + cdbmake_pack(cdbm->final + 8 * b,pos); + cdbmake_pack(cdbm->final + 8 * b + 4,len); + + if (len) { + for (j = 0;j < len;++j) + cdbm->hash[j].h = cdbm->hash[j].p = 0; + + hp = cdbm->split + cdbm->start[b]; + for (j = 0;j < count;++j) { + where = (hp->h >> 8) % len; + while (cdbm->hash[where].p) + if (++where == len) + where = 0; + cdbm->hash[where] = *hp++; + } + } + + return len; +} diff --git a/cdbmake_hash.c b/cdbmake_hash.c new file mode 100644 index 0000000..f9dc3e5 --- /dev/null +++ b/cdbmake_hash.c @@ -0,0 +1,10 @@ +#include "cdbmake.h" + +uint32 cdbmake_hashadd(h,c) +uint32 h; +unsigned int c; +{ + h += (h << 5); + h ^= (uint32) (unsigned char) c; + return h; +} diff --git a/cdbmake_pack.c b/cdbmake_pack.c new file mode 100644 index 0000000..04b5f5b --- /dev/null +++ b/cdbmake_pack.c @@ -0,0 +1,11 @@ +#include "cdbmake.h" + +void cdbmake_pack(buf,num) +unsigned char *buf; +uint32 num; +{ + *buf++ = num; num >>= 8; + *buf++ = num; num >>= 8; + *buf++ = num; num >>= 8; + *buf = num; +} diff --git a/cdbmss.c b/cdbmss.c new file mode 100644 index 0000000..2d8f367 --- /dev/null +++ b/cdbmss.c @@ -0,0 +1,65 @@ +#include "readwrite.h" +#include "seek.h" +#include "alloc.h" +#include "cdbmss.h" + +int cdbmss_start(c,fd) +struct cdbmss *c; +int fd; +{ + cdbmake_init(&c->cdbm); + c->fd = fd; + c->pos = sizeof(c->cdbm.final); + substdio_fdbuf(&c->ss,write,fd,c->ssbuf,sizeof(c->ssbuf)); + return seek_set(fd,(seek_pos) c->pos); +} + +int cdbmss_add(c,key,keylen,data,datalen) +struct cdbmss *c; +unsigned char *key; +unsigned int keylen; +unsigned char *data; +unsigned int datalen; +{ + uint32 h; + int i; + + cdbmake_pack(c->packbuf,(uint32) keylen); + cdbmake_pack(c->packbuf + 4,(uint32) datalen); + if (substdio_put(&c->ss,c->packbuf,8) == -1) return -1; + if (substdio_put(&c->ss,key,keylen) == -1) return -1; + if (substdio_put(&c->ss,data,datalen) == -1) return -1; + + h = CDBMAKE_HASHSTART; + for (i = 0;i < keylen;++i) + h = cdbmake_hashadd(h,(unsigned int) key[i]); + + if (!cdbmake_add(&c->cdbm,h,c->pos,alloc)) return -1; + + c->pos += 8 + keylen + datalen; /* XXX: overflow? */ + return 0; +} + +int cdbmss_finish(c) +struct cdbmss *c; +{ + int i; + uint32 len; + uint32 u; + + if (!cdbmake_split(&c->cdbm,alloc)) return -1; + + for (i = 0;i < 256;++i) { + len = cdbmake_throw(&c->cdbm,c->pos,i); + for (u = 0;u < len;++u) { + cdbmake_pack(c->packbuf,c->cdbm.hash[u].h); + cdbmake_pack(c->packbuf + 4,c->cdbm.hash[u].p); + if (substdio_put(&c->ss,c->packbuf,8) == -1) return -1; + c->pos += 8; /* XXX: overflow? */ + } + } + + if (substdio_flush(&c->ss) == -1) return -1; + if (seek_begin(c->fd) == -1) return -1; + return substdio_putflush(&c->ss,c->cdbm.final,sizeof(c->cdbm.final)); +} diff --git a/cdbmss.h b/cdbmss.h new file mode 100644 index 0000000..5e6bdf4 --- /dev/null +++ b/cdbmss.h @@ -0,0 +1,16 @@ +#ifndef CDBMSS_H +#define CDBMSS_H + +#include "cdbmake.h" +#include "substdio.h" + +struct cdbmss { + char ssbuf[1024]; + struct cdbmake cdbm; + substdio ss; + char packbuf[8]; + uint32 pos; + int fd; +} ; + +#endif diff --git a/coe.c b/coe.c new file mode 100644 index 0000000..d855158 --- /dev/null +++ b/coe.c @@ -0,0 +1,8 @@ +#include +#include "coe.h" + +int coe(fd) +int fd; +{ + return fcntl(fd,F_SETFD,1); +} diff --git a/coe.h b/coe.h new file mode 100644 index 0000000..1559bc1 --- /dev/null +++ b/coe.h @@ -0,0 +1,6 @@ +#ifndef COE_H +#define COE_H + +extern int coe(); + +#endif 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-qmail b/conf-qmail new file mode 100644 index 0000000..0cdd23c --- /dev/null +++ b/conf-qmail @@ -0,0 +1,6 @@ +/var/qmail + +This is the qmail home directory. + +The fastforward programs will be installed in the bin subdirectory; they +also need to know where qmail is so that they can forward mail properly. diff --git a/control.c b/control.c new file mode 100644 index 0000000..b655352 --- /dev/null +++ b/control.c @@ -0,0 +1,130 @@ +#include "readwrite.h" +#include "open.h" +#include "getln.h" +#include "stralloc.h" +#include "substdio.h" +#include "error.h" +#include "control.h" +#include "alloc.h" +#include "scan.h" + +static char inbuf[64]; +static stralloc line = {0}; +static stralloc me = {0}; +static int meok = 0; + +static void striptrailingwhitespace(sa) +stralloc *sa; +{ + while (sa->len > 0) + switch(sa->s[sa->len - 1]) + { + case '\n': case ' ': case '\t': + --sa->len; + break; + default: + return; + } +} + +int control_init() +{ + int r; + r = control_readline(&me,"control/me"); + if (r == 1) meok = 1; + return r; +} + +int control_rldef(sa,fn,flagme,def) +stralloc *sa; +char *fn; +int flagme; +char *def; +{ + int r; + r = control_readline(sa,fn); + if (r) return r; + if (flagme) if (meok) return stralloc_copy(sa,&me) ? 1 : -1; + if (def) return stralloc_copys(sa,def) ? 1 : -1; + return r; +} + +int control_readline(sa,fn) +stralloc *sa; +char *fn; +{ + substdio ss; + int fd; + int match; + + fd = open_read(fn); + if (fd == -1) { if (errno == error_noent) return 0; return -1; } + + substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf)); + + if (getln(&ss,sa,&match,'\n') == -1) { close(fd); return -1; } + + striptrailingwhitespace(sa); + close(fd); + return 1; +} + +int control_readint(i,fn) +int *i; +char *fn; +{ + unsigned long u; + switch(control_readline(&line,fn)) + { + case 0: return 0; + case -1: return -1; + } + if (!stralloc_0(&line)) return -1; + if (!scan_ulong(line.s,&u)) return 0; + *i = u; + return 1; +} + +int control_readfile(sa,fn,flagme) +stralloc *sa; +char *fn; +int flagme; +{ + substdio ss; + int fd; + int match; + + if (!stralloc_copys(sa,"")) return -1; + + fd = open_read(fn); + if (fd == -1) + { + if (errno == error_noent) + { + if (flagme && meok) + { + if (!stralloc_copy(sa,&me)) return -1; + if (!stralloc_0(sa)) return -1; + return 1; + } + return 0; + } + return -1; + } + + substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf)); + + for (;;) + { + if (getln(&ss,&line,&match,'\n') == -1) break; + if (!match && !line.len) { close(fd); return 1; } + striptrailingwhitespace(&line); + if (!stralloc_0(&line)) break; + if (line.s[0]) + if (line.s[0] != '#') + if (!stralloc_cat(sa,&line)) break; + if (!match) { close(fd); return 1; } + } + close(fd); + return -1; +} diff --git a/control.h b/control.h new file mode 100644 index 0000000..7cba89b --- /dev/null +++ b/control.h @@ -0,0 +1,10 @@ +#ifndef CONTROL_H +#define CONTROL_H + +extern int control_init(); +extern int control_readline(); +extern int control_rldef(); +extern int control_readint(); +extern int control_readfile(); + +#endif 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/envread.c b/envread.c new file mode 100644 index 0000000..80185de --- /dev/null +++ b/envread.c @@ -0,0 +1,30 @@ +#include "env.h" +#include "str.h" + +extern /*@null@*/char *env_get(s) +char *s; +{ + int i; + unsigned int slen; + char *envi; + + slen = str_len(s); + for (i = 0;envi = environ[i];++i) + if ((!str_diffn(s,envi,slen)) && (envi[slen] == '=')) + return envi + slen + 1; + return 0; +} + +extern char *env_pick() +{ + return environ[0]; +} + +extern char *env_findeq(s) +char *s; +{ + for (;*s;++s) + if (*s == '=') + return s; + return 0; +} diff --git a/error.c b/error.c new file mode 100644 index 0000000..d51304f --- /dev/null +++ b/error.c @@ -0,0 +1,95 @@ +#include +#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_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/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/fastforward.1 b/fastforward.1 new file mode 100644 index 0000000..d4be2e5 --- /dev/null +++ b/fastforward.1 @@ -0,0 +1,119 @@ +.TH fastforward 1 +.SH NAME +fastforward \- forward mail according to a cdb database +.SH SYNOPSIS +in +.BR .qmail-default : +.B | fastforward +[ +.B \-nNpPdD +] +.I cdb +.SH DESCRIPTION +.B fastforward +forwards each incoming message +according to instructions in +.I cdb +created by +.BR setforward . + +If there is no forwarding instruction in +.I cdb +for the incoming recipient address, +.B fastforward +will bounce the message. + +You can override +.B .qmail-default +with a specific +.BR .qmail-\fIrecipient ; +see +.BR dot-qmail (5). + +Warning to system administrators: +Messages do not reach +.B ~alias/.qmail-default +unless they are controlled by the +.B alias +user. +See +.BR qmail-getpw (8). + +.B SECURITY WARNING: +If +.I cdb +includes instructions pointing to a mailing list owned by another user, +that user gains some amount of control over +.BR fastforward 's +behavior. +In particular, he can force +.B fastforward +to open any file that you can access, +and to read any world-readable file that you own, +even if the file is in a world-inaccessible directory. +.SH "OPTIONS" +.TP 5 +.B \-n +No delivery. +.B fastforward +will print a description of its actions, +but will not actually read or forward a message. +.TP +.B \-N +(Default.) +Forward a message as usual. +.TP +.B \-p +Pass through. +If +.B fastforward +does not find the recipient in +.IR cdb , +it exits 0, +giving the message to further commands in +.BR .qmail-default . +If +.B fastforward +finds the recipient, +it forwards the message and exits 99, +so that further commands are skipped. +.TP +.B \-P +(Default.) +Do not pass through. +If +.B fastforward +finds the recipient, +it forwards the message and exits 0. +Otherwise it bounces the message. +.TP +.B \-d +Use +.B $DEFAULT@$HOST +as the recipient address, or +.B $EXT@$HOST +if +.B $DEFAULT +is not set. +.TP +.B \-D +(Default.) +Use +.B $RECIPIENT +as the recipient address. +.SH VERSION +This is +.B fastforward +0.51. +The +.B fastforward +home page is +.BR http://pobox.com/~djb/fastforward.html . +.SH "SEE ALSO" +newaliases(1), +printforward(1), +setforward(1), +dot-qmail(5), +qmail-command(8), +qmail-local(8), +qmail-getpw(8) diff --git a/fastforward.c b/fastforward.c new file mode 100644 index 0000000..e4ecab2 --- /dev/null +++ b/fastforward.c @@ -0,0 +1,408 @@ +#include +#include +#include "stralloc.h" +#include "substdio.h" +#include "subfd.h" +#include "strset.h" +#include "sgetopt.h" +#include "readwrite.h" +#include "exit.h" +#include "strerr.h" +#include "env.h" +#include "sig.h" +#include "qmail.h" +#include "fmt.h" +#include "case.h" +#include "alloc.h" +#include "coe.h" +#include "seek.h" +#include "wait.h" +#include "fork.h" + +#define FATAL "fastforward: fatal: " + +void usage() +{ + strerr_die1x(100,"fastforward: usage: fastforward [ -nNpP ] data.cdb"); +} +void nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +void print(s) +char *s; +{ + char ch; + while (ch = *s++) { + substdio_put(subfderr,&ch,1); + } +} + +void printsafe(s) +char *s; +{ + char ch; + while (ch = *s++) { + if (ch < 32) ch = '_'; + substdio_put(subfderr,&ch,1); + } +} + +struct qmail qq; +char qp[FMT_ULONG]; +char qqbuf[1]; + +int qqwrite(fd,buf,len) int fd; char *buf; int len; +{ + qmail_put(&qq,buf,len); + return len; +} + +substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof qqbuf); + +char messbuf[4096]; +substdio ssmess = SUBSTDIO_FDBUF(read,0,messbuf,sizeof messbuf); + +int flagdeliver = 1; +int flagpassthrough = 0; + +char *dtline; +stralloc sender = {0}; +stralloc programs = {0}; +stralloc forward = {0}; + +strset done; +stralloc todo = {0}; + +stralloc mailinglist = {0}; + +void dofile(fn) +char *fn; +{ + int fd; + struct stat st; + int i; + int j; + + if (!stralloc_copys(&mailinglist,"")) nomem(); + + fd = open_read(fn); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to read ",fn,": "); + if (fstat(fd,&st) == -1) + strerr_die4sys(111,FATAL,"unable to stat ",fn,": "); + if ((st.st_mode & 0444) != 0444) + strerr_die3x(111,FATAL,fn," is not world-readable"); + if (slurpclose(fd,&mailinglist,1024) == -1) + strerr_die4sys(111,FATAL,"unable to read ",fn,": "); + + i = 0; + for (j = 0;j < mailinglist.len;++j) + if (!mailinglist.s[j]) { + if ((mailinglist.s[i] == '.') || (mailinglist.s[i] == '/')) { + if (!stralloc_cats(&todo,mailinglist.s + i)) nomem(); + if (!stralloc_0(&todo)) nomem(); + } + else if ((mailinglist.s[i] == '&') && (j - i < 900)) { + if (!stralloc_cats(&todo,mailinglist.s + i)) nomem(); + if (!stralloc_0(&todo)) nomem(); + } + i = j + 1; + } +} + +char *fncdb; +int fdcdb; +stralloc key = {0}; +uint32 dlen; +stralloc data = {0}; + +void cdbreaderror() +{ + strerr_die4sys(111,FATAL,"unable to read ",fncdb,": "); +} + +int findtarget(flagwild,prepend,addr) +int flagwild; +char *prepend; +char *addr; +{ + int r; + int at; + + if (!stralloc_copys(&key,prepend)) nomem(); + if (!stralloc_cats(&key,addr)) nomem(); + case_lowerb(key.s,key.len); + + r = cdb_seek(fdcdb,key.s,key.len,&dlen); + if (r == -1) cdbreaderror(); + if (r) return 1; + + if (!flagwild) return 0; + at = str_rchr(addr,'@'); + if (!addr[at]) return 0; + + if (!stralloc_copys(&key,prepend)) nomem(); + if (!stralloc_cats(&key,addr + at)) nomem(); + case_lowerb(key.s,key.len); + + r = cdb_seek(fdcdb,key.s,key.len,&dlen); + if (r == -1) cdbreaderror(); + if (r) return 1; + + if (!stralloc_copys(&key,prepend)) nomem(); + if (!stralloc_catb(&key,addr,at + 1)) nomem(); + case_lowerb(key.s,key.len); + + r = cdb_seek(fdcdb,key.s,key.len,&dlen); + if (r == -1) cdbreaderror(); + if (r) return 1; + + return 0; +} + +int gettarget(flagwild,prepend,addr) +int flagwild; +char *prepend; +char *addr; +{ + if (!findtarget(flagwild,prepend,addr)) return 0; + + if (!stralloc_ready(&data,(unsigned int) dlen)) nomem(); + data.len = dlen; + if (cdb_bread(fdcdb,data.s,data.len) == -1) cdbreaderror(); + + return 1; +} + +void doprogram(arg) +char *arg; +{ + char *args[5]; + int child; + int wstat; + + if (!flagdeliver) { + print("run "); + printsafe(arg); + print("\n"); + substdio_flush(subfderr); + return; + } + + if (*arg == '!') { + args[0] = "preline"; + args[1] = "sh"; + args[2] = "-c"; + args[3] = arg + 1; + args[4] = 0; + } + else { + args[0] = "sh"; + args[1] = "-c"; + args[2] = arg + 1; + args[3] = 0; + } + + switch(child = vfork()) { + case -1: + strerr_die2sys(111,FATAL,"unable to fork: "); + case 0: + sig_pipedefault(); + execvp(*args,args); + strerr_die4sys(111,FATAL,"unable to run ",arg,": "); + } + + wait_pid(&wstat,child); + if (wait_crashed(wstat)) + strerr_die4sys(111,FATAL,"child crashed in ",arg,": "); + + switch(wait_exitcode(wstat)) { + case 64: case 65: case 70: case 76: case 77: case 78: case 112: + case 100: _exit(100); + case 0: break; + default: _exit(111); + } + + if (seek_begin(0) == -1) + strerr_die2sys(111,FATAL,"unable to rewind input: "); +} + +void dodata() +{ + int i; + int j; + i = 0; + for (j = 0;j < data.len;++j) + if (!data.s[j]) { + if ((data.s[i] == '|') || (data.s[i] == '!')) + doprogram(data.s + i); + else if ((data.s[i] == '.') || (data.s[i] == '/')) { + if (!stralloc_cats(&todo,data.s + i)) nomem(); + if (!stralloc_0(&todo)) nomem(); + } + else if ((data.s[i] == '&') && (j - i < 900)) { + if (!stralloc_cats(&todo,data.s + i)) nomem(); + if (!stralloc_0(&todo)) nomem(); + } + i = j + 1; + } +} + +void dorecip(addr) +char *addr; +{ + + if (!findtarget(0,"?",addr)) + if (gettarget(0,":",addr)) { + dodata(); + return; + } + if (!stralloc_cats(&forward,addr)) nomem(); + if (!stralloc_0(&forward)) nomem(); +} + +void doorigrecip(addr) +char *addr; +{ + if (sender.len) + if ((sender.len != 4) || byte_diff(sender.s,4,"#@[]")) + if (gettarget(1,"?",addr)) + if (!stralloc_copy(&sender,&data)) nomem(); + if (!gettarget(1,":",addr)) + if (flagpassthrough) + _exit(0); + else + strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)"); + dodata(); +} + +stralloc recipient = {0}; +int flagdefault = 0; + +void main(argc,argv) +int argc; +char **argv; +{ + int opt; + char *x; + int i; + + sig_pipeignore(); + + dtline = env_get("DTLINE"); + if (!dtline) dtline = ""; + + x = env_get("SENDER"); + if (!x) x = "original envelope sender"; + if (!stralloc_copys(&sender,x)) nomem(); + + if (!stralloc_copys(&forward,"")) nomem(); + if (!strset_init(&done)) nomem(); + + while ((opt = getopt(argc,argv,"nNpPdD")) != opteof) + switch(opt) { + case 'n': flagdeliver = 0; break; + case 'N': flagdeliver = 1; break; + case 'p': flagpassthrough = 1; break; + case 'P': flagpassthrough = 0; break; + case 'd': flagdefault = 1; break; + case 'D': flagdefault = 0; break; + default: usage(); + } + argv += optind; + + fncdb = *argv; + if (!fncdb) usage(); + fdcdb = open_read(fncdb); + if (fdcdb == -1) cdbreaderror(); + coe(fdcdb); + + if (flagdefault) { + x = env_get("DEFAULT"); + if (!x) x = env_get("EXT"); + if (!x) strerr_die2x(100,FATAL,"$DEFAULT or $EXT must be set"); + if (!stralloc_copys(&recipient,x)) nomem(); + if (!stralloc_cats(&recipient,"@")) nomem(); + x = env_get("HOST"); + if (!x) strerr_die2x(100,FATAL,"$HOST must be set"); + if (!stralloc_cats(&recipient,x)) nomem(); + if (!stralloc_0(&recipient)) nomem(); + x = recipient.s; + } + else { + x = env_get("RECIPIENT"); + if (!x) strerr_die2x(100,FATAL,"$RECIPIENT must be set"); + } + if (!strset_add(&done,x)) nomem(); + doorigrecip(x); + + while (todo.len) { + i = todo.len - 1; + while ((i > 0) && todo.s[i - 1]) --i; + todo.len = i; + + if (strset_in(&done,todo.s + i)) continue; + + x = alloc(str_len(todo.s + i) + 1); + if (!x) nomem(); + str_copy(x,todo.s + i); + if (!strset_add(&done,x)) nomem(); + + x = todo.s + i; + if (*x == 0) + continue; + else if ((*x == '.') || (*x == '/')) + dofile(x); + else + dorecip(x + 1); + } + + if (!forward.len) { + if (!flagdeliver) { + print("no forwarding\n"); + substdio_flush(subfderr); + } + _exit(flagpassthrough ? 99 : 0); + } + + if (!stralloc_0(&sender)) nomem(); + + if (!flagdeliver) { + print("from <"); + printsafe(sender.s); + print(">\n"); + while (forward.len) { + i = forward.len - 1; + while ((i > 0) && forward.s[i - 1]) --i; + forward.len = i; + print("to <"); + printsafe(forward.s + i); + print(">\n"); + } + substdio_flush(subfderr); + _exit(flagpassthrough ? 99 : 0); + } + + if (qmail_open(&qq) == -1) + strerr_die2sys(111,FATAL,"unable to fork: "); + qmail_puts(&qq,dtline); + if (substdio_copy(&ssqq,&ssmess) != 0) + strerr_die2sys(111,FATAL,"unable to read message: "); + substdio_flush(&ssqq); + qp[fmt_ulong(qp,qmail_qp(&qq))] = 0; + + qmail_from(&qq,sender.s); + + while (forward.len) { + i = forward.len - 1; + while ((i > 0) && forward.s[i - 1]) --i; + forward.len = i; + qmail_to(&qq,forward.s + i); + } + + x = qmail_close(&qq); + if (*x) strerr_die2x(*x == 'D' ? 100 : 111,FATAL,x + 1); + strerr_die2x(flagpassthrough ? 99 : 0,"fastforward: qp ",qp); +} diff --git a/fd.h b/fd.h new file mode 100644 index 0000000..c3d6e3e --- /dev/null +++ b/fd.h @@ -0,0 +1,7 @@ +#ifndef FD_H +#define FD_H + +extern int fd_copy(); +extern int fd_move(); + +#endif diff --git a/fd_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_move.c b/fd_move.c new file mode 100644 index 0000000..1aa557f --- /dev/null +++ b/fd_move.c @@ -0,0 +1,11 @@ +#include "fd.h" + +int fd_move(to,from) +int to; +int from; +{ + if (to == from) return 0; + if (fd_copy(to,from) == -1) return -1; + close(from); + return 0; +} diff --git a/find-systype.sh b/find-systype.sh new file mode 100644 index 0000000..16266d3 --- /dev/null +++ b/find-systype.sh @@ -0,0 +1,144 @@ +# oper-:arch-:syst-:chip-:kern- +# oper = operating system type; e.g., sunos-4.1.4 +# arch = machine language; e.g., sparc +# syst = which binaries can run; e.g., sun4 +# chip = chip model; e.g., micro-2-80 +# kern = kernel version; e.g., sun4m +# dependence: arch --- chip +# \ \ +# oper --- syst --- kern +# so, for example, syst is interpreted in light of oper, but chip is not. +# anyway, no slashes, no extra colons, no uppercase letters. +# the point of the extra -'s is to ease parsing: can add hierarchies later. +# e.g., *:i386-*:*:pentium-*:* would handle pentium-100 as well as pentium, +# and i386-486 (486s do have more instructions, you know) as well as i386. +# the idea here is to include ALL useful available information. + +exec 2>/dev/null +sys="`uname -s | tr '/:[A-Z]' '..[a-z]'`" +if [ x"$sys" != x ] +then + unamer="`uname -r | tr /: ..`" + unamem="`uname -m | tr /: ..`" + unamev="`uname -v | tr /: ..`" + + case "$sys" in + bsd.os) + # in bsd 4.4, uname -v does not have useful info. + # in bsd 4.4, uname -m is arch, not chip. + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" + kern="" + ;; + freebsd) + # see above about bsd 4.4 + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" # hopefully + kern="" + ;; + netbsd) + # see above about bsd 4.4 + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" # hopefully + kern="" + ;; + linux) + # as in bsd 4.4, uname -v does not have useful info. + oper="$sys-$unamer" + syst="" + chip="$unamem" + kern="" + case "$chip" in + i386|i486|i586|i686) + arch="i386" + ;; + alpha) + arch="alpha" + ;; + esac + ;; + aix) + # naturally IBM has to get uname -r and uname -v backwards. dorks. + oper="$sys-$unamev-$unamer" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + sunos) + oper="$sys-$unamer-$unamev" + arch="`(uname -p || mach) | tr /: ..`" + syst="`arch | tr /: ..`" + chip="$unamem" # this is wrong; is there any way to get the real info? + kern="`arch -k | tr /: ..`" + ;; + unix_sv) + oper="$sys-$unamer-$unamev" + arch="`uname -m`" + syst="" + chip="$unamem" + kern="" + ;; + *) + oper="$sys-$unamer-$unamev" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + esac +else + $CC -c trycpp.c + $LD -o trycpp trycpp.o + case `./trycpp` in + nextstep) + oper="nextstep-`hostinfo | sed -n 's/^[ ]*NeXT Mach \([^:]*\):.*$/\1/p'`" + arch="`hostinfo | sed -n 's/^Processor type: \(.*\) (.*)$/\1/p' | tr /: ..`" + syst="" + chip="`hostinfo | sed -n 's/^Processor type: .* (\(.*\))$/\1/p' | tr ' /:' '...'`" + kern="" + ;; + *) + oper="unknown" + arch="" + syst="" + chip="" + kern="" + ;; + esac + rm -f trycpp.o trycpp +fi + +case "$chip" in +80486) + # let's try to be consistent here. (BSD/OS) + chip=i486 + ;; +i486DX) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx + ;; +i486.DX2) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx2 + ;; +Intel.586) + # no, you nitwits, there is no such chip. (NeXTStep) + chip=pentium + ;; +i586) + # no, you nitwits, there is no such chip. (Linux) + chip=pentium + ;; +i686) + # STOP SAYING THAT! (Linux) + chip=ppro +esac + +echo "$oper-:$arch-:$syst-:$chip-:$kern-" | tr ' [A-Z]' '.[a-z]' diff --git a/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_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.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/gen_alloc.h b/gen_alloc.h new file mode 100644 index 0000000..b94a956 --- /dev/null +++ b/gen_alloc.h @@ -0,0 +1,7 @@ +#ifndef GEN_ALLOC_H +#define GEN_ALLOC_H + +#define GEN_ALLOC_typedef(ta,type,field,len,a) \ + typedef struct ta { type *field; unsigned int len; unsigned int a; } ta; + +#endif diff --git a/gen_allocdefs.h b/gen_allocdefs.h new file mode 100644 index 0000000..783a9b1 --- /dev/null +++ b/gen_allocdefs.h @@ -0,0 +1,34 @@ +#ifndef GEN_ALLOC_DEFS_H +#define GEN_ALLOC_DEFS_H + +#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \ +int ta_ready(x,n) register ta *x; register unsigned int n; \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \ +int ta_rplus(x,n) register ta *x; register unsigned int n; \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; n += x->len; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \ +int ta_append(x,i) register ta *x; register type *i; \ +{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; } + +#endif diff --git a/getln.c b/getln.c new file mode 100644 index 0000000..c5cb097 --- /dev/null +++ b/getln.c @@ -0,0 +1,20 @@ +#include "substdio.h" +#include "byte.h" +#include "stralloc.h" +#include "getln.h" + +int getln(ss,sa,match,sep) +register substdio *ss; +register stralloc *sa; +int *match; +int sep; +{ + char *cont; + unsigned int clen; + + if (getln2(ss,sa,&cont,&clen,sep) == -1) return -1; + if (!clen) { *match = 0; return 0; } + if (!stralloc_catb(sa,cont,clen)) return -1; + *match = 1; + return 0; +} diff --git a/getln.h b/getln.h new file mode 100644 index 0000000..cf4f934 --- /dev/null +++ b/getln.h @@ -0,0 +1,7 @@ +#ifndef GETLN_H +#define GETLN_H + +extern int getln(); +extern int getln2(); + +#endif diff --git a/getln2.c b/getln2.c new file mode 100644 index 0000000..9e576e9 --- /dev/null +++ b/getln2.c @@ -0,0 +1,31 @@ +#include "substdio.h" +#include "stralloc.h" +#include "byte.h" +#include "getln.h" + +int getln2(ss,sa,cont,clen,sep) +register substdio *ss; +register stralloc *sa; +/*@out@*/char **cont; +/*@out@*/unsigned int *clen; +int sep; +{ + register char *x; + register unsigned int i; + int n; + + if (!stralloc_ready(sa,0)) return -1; + sa->len = 0; + + for (;;) { + n = substdio_feed(ss); + if (n < 0) return -1; + if (n == 0) { *clen = 0; return 0; } + x = substdio_PEEK(ss); + i = byte_chr(x,n,sep); + if (i < n) { substdio_SEEK(ss,*clen = i + 1); *cont = x; return 0; } + if (!stralloc_readyplus(sa,n)) return -1; + i = sa->len; + sa->len = i + substdio_get(ss,sa->s + i,n); + } +} diff --git a/hier.c b/hier.c new file mode 100644 index 0000000..b5caa7f --- /dev/null +++ b/hier.c @@ -0,0 +1,39 @@ +#include "auto_qmail.h" + +void hier() +{ + h(auto_qmail,-1,-1,0755); + + d(auto_qmail,"bin",-1,-1,0755); + d(auto_qmail,"doc",-1,-1,0755); + d(auto_qmail,"doc/fastforward",-1,-1,0755); + d(auto_qmail,"man",-1,-1,0755); + d(auto_qmail,"man/man1",-1,-1,0755); + d(auto_qmail,"man/cat1",-1,-1,0755); + + c(auto_qmail,"bin","fastforward",-1,-1,0755); + c(auto_qmail,"bin","printforward",-1,-1,0755); + c(auto_qmail,"bin","setforward",-1,-1,0755); + c(auto_qmail,"bin","newaliases",-1,-1,0755); + c(auto_qmail,"bin","printmaillist",-1,-1,0755); + c(auto_qmail,"bin","setmaillist",-1,-1,0755); + c(auto_qmail,"bin","newinclude",-1,-1,0755); + + c(auto_qmail,"doc/fastforward","ALIASES",-1,-1,0644); + + c(auto_qmail,"man/man1","fastforward.1",-1,-1,0644); + c(auto_qmail,"man/man1","printforward.1",-1,-1,0644); + c(auto_qmail,"man/man1","setforward.1",-1,-1,0644); + c(auto_qmail,"man/man1","newaliases.1",-1,-1,0644); + c(auto_qmail,"man/man1","printmaillist.1",-1,-1,0644); + c(auto_qmail,"man/man1","setmaillist.1",-1,-1,0644); + c(auto_qmail,"man/man1","newinclude.1",-1,-1,0644); + + c(auto_qmail,"man/cat1","fastforward.0",-1,-1,0644); + c(auto_qmail,"man/cat1","printforward.0",-1,-1,0644); + c(auto_qmail,"man/cat1","setforward.0",-1,-1,0644); + c(auto_qmail,"man/cat1","newaliases.0",-1,-1,0644); + c(auto_qmail,"man/cat1","printmaillist.0",-1,-1,0644); + c(auto_qmail,"man/cat1","setmaillist.0",-1,-1,0644); + c(auto_qmail,"man/cat1","newinclude.0",-1,-1,0644); +} diff --git a/install.c b/install.c new file mode 100644 index 0000000..beec00c --- /dev/null +++ b/install.c @@ -0,0 +1,111 @@ +#include "substdio.h" +#include "strerr.h" +#include "error.h" +#include "open.h" +#include "readwrite.h" +#include "exit.h" + +extern void hier(); + +#define FATAL "install: fatal: " + +int fdsourcedir = -1; + +void h(home,uid,gid,mode) +char *home; +int uid; +int gid; +int mode; +{ + if (mkdir(home,0700) == -1) + if (errno != error_exist) + strerr_die4sys(111,FATAL,"unable to mkdir ",home,": "); + if (chown(home,uid,gid) == -1) + strerr_die4sys(111,FATAL,"unable to chown ",home,": "); + if (chmod(home,mode) == -1) + strerr_die4sys(111,FATAL,"unable to chmod ",home,": "); +} + +void d(home,subdir,uid,gid,mode) +char *home; +char *subdir; +int uid; +int gid; +int mode; +{ + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + if (mkdir(subdir,0700) == -1) + if (errno != error_exist) + strerr_die6sys(111,FATAL,"unable to mkdir ",home,"/",subdir,": "); + if (chown(subdir,uid,gid) == -1) + strerr_die6sys(111,FATAL,"unable to chown ",home,"/",subdir,": "); + if (chmod(subdir,mode) == -1) + strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",subdir,": "); +} + +char inbuf[SUBSTDIO_INSIZE]; +char outbuf[SUBSTDIO_OUTSIZE]; +substdio ssin; +substdio ssout; + +void c(home,subdir,file,uid,gid,mode) +char *home; +char *subdir; +char *file; +int uid; +int gid; +int mode; +{ + int fdin; + int fdout; + + if (fchdir(fdsourcedir) == -1) + strerr_die2sys(111,FATAL,"unable to switch back to source directory: "); + + fdin = open_read(file); + if (fdin == -1) + strerr_die4sys(111,FATAL,"unable to read ",file,": "); + substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof inbuf); + + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + if (chdir(subdir) == -1) + strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": "); + + fdout = open_trunc(file); + if (fdout == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof outbuf); + + switch(substdio_copy(&ssout,&ssin)) { + case -2: + strerr_die4sys(111,FATAL,"unable to read ",file,": "); + case -3: + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + } + + close(fdin); + if (substdio_flush(&ssout) == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + if (fsync(fdout) == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + if (close(fdout) == -1) /* NFS silliness */ + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + + if (chown(file,uid,gid) == -1) + strerr_die6sys(111,FATAL,"unable to chown .../",subdir,"/",file,": "); + if (chmod(file,mode) == -1) + strerr_die6sys(111,FATAL,"unable to chmod .../",subdir,"/",file,": "); +} + +void main() +{ + fdsourcedir = open_read("."); + if (fdsourcedir == -1) + strerr_die2sys(111,FATAL,"unable to open current directory: "); + + umask(077); + hier(); + _exit(0); +} diff --git a/instcheck.c b/instcheck.c new file mode 100644 index 0000000..0b77e45 --- /dev/null +++ b/instcheck.c @@ -0,0 +1,83 @@ +#include +#include +#include "strerr.h" +#include "error.h" +#include "readwrite.h" +#include "exit.h" + +extern void hier(); + +#define FATAL "instcheck: fatal: " +#define WARNING "instcheck: warning: " + +void perm(prefix1,prefix2,prefix3,file,type,uid,gid,mode) +char *prefix1; +char *prefix2; +char *prefix3; +char *file; +int type; +int uid; +int gid; +int mode; +{ + struct stat st; + + if (stat(file,&st) == -1) { + if (errno == error_noent) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," does not exist",0); + else + strerr_warn4(WARNING,"unable to stat .../",file,": ",&strerr_sys); + return; + } + + if ((uid != -1) && (st.st_uid != uid)) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong owner",0); + if ((gid != -1) && (st.st_gid != gid)) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong group",0); + if ((st.st_mode & 07777) != mode) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong permissions",0); + if ((st.st_mode & S_IFMT) != type) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong type",0); +} + +void h(home,uid,gid,mode) +char *home; +int uid; +int gid; +int mode; +{ + perm("","","",home,S_IFDIR,uid,gid,mode); +} + +void d(home,subdir,uid,gid,mode) +char *home; +char *subdir; +int uid; +int gid; +int mode; +{ + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + perm("",home,"/",subdir,S_IFDIR,uid,gid,mode); +} + +void c(home,subdir,file,uid,gid,mode) +char *home; +char *subdir; +char *file; +int uid; +int gid; +int mode; +{ + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + if (chdir(subdir) == -1) + strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": "); + perm(".../",subdir,"/",file,S_IFREG,uid,gid,mode); +} + +void main() +{ + hier(); + _exit(0); +} 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/newaliases.1 b/newaliases.1 new file mode 100644 index 0000000..c94868f --- /dev/null +++ b/newaliases.1 @@ -0,0 +1,366 @@ +.TH newaliases 1 +.SH NAME +newaliases \- create a forwarding database from /etc/aliases +.SH SYNOPSIS +.B newaliases +.SH DESCRIPTION +.B newaliases +reads a table of +sendmail-style +forwarding instructions from +.B /etc/aliases +and converts them into a forwarding database in +.BR /etc/aliases.cdb . +The forwarding database can be used by +.BR fastforward . + +For safety, +.B newaliases +writes the forwarding database to +.B /etc/aliases.tmp +and then moves +.B /etc/aliases.tmp +to +.BR /etc/aliases.cdb . +If there is a problem creating +.BR /etc/aliases.tmp , +.B newaliases +complains and leaves +.B /etc/aliases.cdb +alone. +Deliveries can continue using +.B /etc/aliases.cdb +in the meantime. + +.B newaliases +always creates +.B /etc/aliases.cdb +world-readable. + +.B newaliases +makes no attempt to protect against +simultaneous updates of +.BR /etc/aliases.cdb . +.SH "INSTRUCTION FORMAT" +.B newaliases +imitates +sendmail's +handling of +.BR /etc/aliases . +For example, + +.EX + root: alice, bill +.EE + +says that mail for +.B root +should be forwarded to +.B alice +and +.BR bill . + +.B COMPATIBILITY WARNING: +.B newaliases +does not support file deliveries. +You can use the file delivery mechanism described in +.B dot-qmail(5) +instead. +.SH "SIMPLE ALIASES" +The simplest type of forwarding instruction +is a line of the form + +.EX + alias: recip +.EE + +Any message sent to +.I alias +will be forwarded to the recipient address +.IR recip . +Addresses are compared to +.I alias +without regard to case. + +Forwarding instructions are cumulative. +If +.I recip +is itself an alias, +messages to +.I alias +will be forwarded the same way as +messages to +.IR recip . +For example, with the following instructions, +messages to +.B postmaster@heaven.af.mil +or +.B root@heaven.af.mil +will be delivered to Bob: + +.EX + postmaster@heaven.af.mil: bob@heaven.af.mil +.EE +.br +.EX + root@heaven.af.mil: postmaster@heaven.af.mil +.EE + +.B COMPATIBILITY WARNING: +With +sendmail, +entries in +.B /etc/aliases +can override usernames. +With +.BR qmail , +if you install +.B fastforward +in +.BR ~alias/.qmail-default , +it will not see addresses that are controlled by other users. +See +.BR qmail-getpw (8). +To change this, see +.BR qmail-users (5). + +.B COMPATIBILITY WARNING: +Various versions of +sendmail +do various strange things with circular alias definitions. +See +.BR setforward (1) +for details on +.BR fastforward 's +behavior. + +.B COMPATIBILITY WARNING: +If there are several forwarding instructions for a single +.IR alias , +sendmail +will complain; +.B fastforward +will silently use the first instruction. +.SH "WILDCARDS" +.I alias +can have the form +.I user@host.dom +for one user at one host, +.I @host.dom +for all users at one host, or +.I user +for one user at all hosts. + +.B COMPATIBILITY WARNING: +sendmail +supports only +.IR user ; +it does not support per-host aliases. +It accepts +.I user@host.dom +if +.I host.dom +is a local host, +but it then treats it the same way as +.IR user , +applying to all local hosts and virtual domains. +.SH "ADDRESS FORMATS" +Addresses in +.B /etc/aliases +are parsed the same way as addresses in RFC 822 message headers. +Parenthesized comments and bracketed addresses are permitted: + +.EX + root: bob (Bob, the postmaster) + joe: Joe Shmoe +.EE + +Addresses with special characters must be quoted: + +.EX + fred: "spaced out mailbox"@heaven.af.mil +.EE + +Address groups are not permitted, +since colons have a different use in +.BR /etc/aliases . + +Any recipient address without a fully qualified domain name is +fed through the +.BR defaulthost , +.BR defaultdomain , +and +.B plusdomain +mechanisms described in +.BR qmail-header (5). + +.B COMPATIBILITY WARNING: +sendmail's +handling of quotes and backslashes violates RFC 821 and RFC 822, +and is not supported by +.BR newaliases . +The +.B qmail-local +delivery mechanism +lets each user manage several addresses, +so there is no need for a special syntax to get around forwarding. +.SH "MULTIPLE RECIPIENTS" +An instruction may list more than one recipient address: + +.EX + alias: recip1, recip2, recip3 +.EE + +Any message sent to +.I alias +will be forwarded to all of the addresses. + +A forwarding instruction may be split across several lines. +Each line past the first must either (1) begin with space or tab +or (2) be empty: + +.EX + hostmaster: +.EE +.br +.EX + fred, +.EE +.br +.EX + joe +.EE + +.B COMPATIBILITY WARNING: +sendmail +requires the colon to be on the first line +of a multi-line forwarding instruction. +.B newaliases +doesn't care whether the colon is present at all. + +.B COMPATIBILITY WARNING: +sendmail +does not permit blank lines in the middle of continuations. +This has the undesirable effect that a blank line behaves differently +from a line containing a single space. +.SH "COMMENTS" +Any line in +.B /etc/aliases +that begins with # is ignored: + +.EX + # this is a comment +.EE + +A comment may be split across several lines. +Each line past the first must either (1) begin with space or tab +or (2) be empty. + +.B COMPATIBILITY WARNING: +sendmail +does not permit continuations of comment lines. +.SH "PROGRAMS" +If a recipient address does not contain a domain name, +and begins with a vertical bar, +.B newaliases +takes the rest of the address as a program to run: + +.EX + weather: "|weather-server" +.EE + +.B fastforward +will run +.B weather-server +when a message arrives for +.BR weather . + +.B COMPATIBILITY WARNING: +Internet addresses can legitimately start with +a slash or vertical bar. +.B newaliases +treats anything with an unquoted @ as an address. +sendmail appears to have various problems +coping with these addresses, +and with commands that contain @ signs. + +.B COMPATIBILITY WARNING: +.B newaliases +does not allow a vertical bar before double quotes. +.SH "INCLUDE FILES" +A recipient address of the form +.B :include:\fIfile +means ``every address listed in +.IR file .'' +(Actually +.B fastforward +reads +.IR file\fB.bin ; +see +.BR newinclude (1) +for further details.) + +Note that +.I file +is read by +.BR fastforward , +not +.BR newaliases , +so the system administrator does not have to run +.B newaliases +every time +.I file +changes. +.I file +must be world-readable +and accessible to +.BR fastforward . + +.B COMPATIBILITY WARNING: +If an +.B :include: +file is unreadable or nonexistent, +sendmail +skips it; +.B fastforward +defers delivery of the message. + +.B COMPATIBILITY WARNING: +sendmail +does not permit spaces inside the literal text +.BR :include: . +.B newaliases +does. + +.B COMPATIBILITY WARNING: +Versions of +sendmail +before V8 did not strip quotes from +.B :include: +filenames. +.SH "ALIAS OWNERS" +If there is an alias for +.BR owner-\fIlist , +any message forwarded through +.I list +will have its envelope sender set to +.BR owner-\fIlist , +so that bounces go back to +.BR owner-\fIlist . + +.B COMPATIBILITY WARNING: +When an alias includes the same recipient both inside and outside +a mailing list, +.B fastforward +sends the message twice, +once with each envelope sender. +sendmail +sends the message only once; +its choice of envelope sender for that recipient +depends on the phase of the moon. +.SH "SEE ALSO" +fastforward(1), +setforward(1), +newinclude(1), +printforward(1), +dot-qmail(5) diff --git a/newaliases.c b/newaliases.c new file mode 100644 index 0000000..3025b01 --- /dev/null +++ b/newaliases.c @@ -0,0 +1,321 @@ +#include "substdio.h" +#include "strerr.h" +#include "stralloc.h" +#include "getln.h" +#include "open.h" +#include "readwrite.h" +#include "token822.h" +#include "control.h" +#include "auto_qmail.h" +#include "case.h" +#include "cdbmss.h" + +#define FATAL "newaliases: fatal: " + +void nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} +void nulbyte() +{ + strerr_die2x(100,FATAL,"NUL bytes are not permitted"); +} +void longaddress() +{ + strerr_die2x(100,FATAL,"addresses over 800 bytes are not permitted"); +} +void writeerr() +{ + strerr_die2sys(111,FATAL,"unable to write to /etc/aliases.tmp: "); +} +void readerr() +{ + strerr_die2sys(111,FATAL,"unable to read /etc/aliases: "); +} +void die_control() +{ + strerr_die2sys(111,FATAL,"unable to read controls: "); +} + +stralloc me = {0}; +stralloc defaulthost = {0}; +stralloc defaultdomain = {0}; +stralloc plusdomain = {0}; + +void readcontrols() +{ + int r; + int fddir; + + fddir = open_read("."); + if (fddir == -1) + strerr_die2sys(111,FATAL,"unable to open current directory: "); + + if (chdir(auto_qmail) == -1) + strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": "); + + r = control_readline(&me,"control/me"); + if (r == -1) die_control(); + if (!r) if (!stralloc_copys(&me,"me")) nomem(); + + r = control_readline(&defaultdomain,"control/defaultdomain"); + if (r == -1) die_control(); + if (!r) if (!stralloc_copy(&defaultdomain,&me)) nomem(); + + r = control_readline(&defaulthost,"control/defaulthost"); + if (r == -1) die_control(); + if (!r) if (!stralloc_copy(&defaulthost,&me)) nomem(); + + r = control_readline(&plusdomain,"control/plusdomain"); + if (r == -1) die_control(); + if (!r) if (!stralloc_copy(&plusdomain,&me)) nomem(); + + if (fchdir(fddir) == -1) + strerr_die2sys(111,FATAL,"unable to set current directory: "); +} + +stralloc target = {0}; +stralloc fulltarget = {0}; +stralloc instr = {0}; + +stralloc cbuf = {0}; +token822_alloc toks = {0}; +token822_alloc tokaddr = {0}; +stralloc address = {0}; + +void gotincl() +{ + token822_reverse(&tokaddr); + if (token822_unquote(&address,&tokaddr) != 1) nomem(); + tokaddr.len = 0; + + if (!address.len) + strerr_die2x(111,FATAL,"empty :include: filenames not permitted"); + if (byte_chr(address.s,address.len,'\0') < address.len) + strerr_die2x(111,FATAL,"NUL not permitted in :include: filenames"); + + if ((address.s[0] != '.') && (address.s[0] != '/')) + if (!stralloc_cats(&instr,"./")) nomem(); + if (!stralloc_cat(&instr,&address)) nomem(); + if (!stralloc_cats(&instr,".bin")) nomem(); + if (!stralloc_0(&instr)) nomem(); +} + +void gotaddr() +{ + int i; + int j; + int flaghasat; + + token822_reverse(&tokaddr); + if (token822_unquote(&address,&tokaddr) != 1) nomem(); + + if (!address.len) + strerr_die2x(111,FATAL,"empty recipient addresses not permitted"); + + flaghasat = 0; + for (i = 0;i < tokaddr.len;++i) + if (tokaddr.t[i].type == TOKEN822_AT) + flaghasat = 1; + + tokaddr.len = 0; + + if (!address.len) return; + + if (!flaghasat) + if (address.s[0] == '/') { + if (!stralloc_0(&address)) nomem(); + strerr_die4x(111,FATAL,"file delivery ",address.s," not supported"); + } + if (!flaghasat) + if (address.s[0] == '|') { + if (byte_chr(address.s,address.len,'\0') < address.len) + strerr_die2x(111,FATAL,"NUL not permitted in program names"); + if (!stralloc_cats(&instr,"!")) nomem(); + if (!stralloc_catb(&instr,address.s + 1,address.len - 1)) nomem(); + if (!stralloc_0(&instr)) nomem(); + return; + } + + + if (target.len) { + if (!stralloc_cats(&instr,"&")) nomem(); + if (!stralloc_cat(&instr,&fulltarget)) nomem(); + if (!stralloc_0(&instr)) nomem(); + } + + if (!flaghasat) + if (!stralloc_cats(&address,"@")) nomem(); + + if (!stralloc_copy(&target,&address)) nomem(); + if (!stralloc_copy(&fulltarget,&address)) nomem(); + + if (fulltarget.s[fulltarget.len - 1] == '@') + if (!stralloc_cat(&fulltarget,&defaulthost)) nomem(); + if (fulltarget.s[fulltarget.len - 1] == '+') { + fulltarget.s[fulltarget.len - 1] = '.'; + if (!stralloc_cat(&fulltarget,&plusdomain)) nomem(); + } + + j = 0; + for (i = 0;i < fulltarget.len;++i) if (fulltarget.s[i] == '@') j = i; + for (i = j;i < fulltarget.len;++i) if (fulltarget.s[i] == '.') break; + if (i == fulltarget.len) { + if (!stralloc_cats(&fulltarget,".")) nomem(); + if (!stralloc_cat(&fulltarget,&defaultdomain)) nomem(); + } + + if (fulltarget.len > 800) longaddress(); + if (byte_chr(fulltarget.s,fulltarget.len,'\0') < fulltarget.len) + strerr_die2x(111,FATAL,"NUL not permitted in recipient addresses"); +} + +stralloc line = {0}; +stralloc newline = {0}; +int match; + +void parseerr() +{ + if (!stralloc_0(&line)) nomem(); + strerr_die3x(111,FATAL,"unable to parse this line: ",line.s); +} + +void parseline() +{ + int wordok; + struct token822 *t; + struct token822 *beginning; + + switch(token822_parse(&toks,&line,&cbuf)) { + case -1: nomem(); + case 0: parseerr(); + } + + beginning = toks.t; + t = toks.t + toks.len; + wordok = 1; + + if (!token822_readyplus(&tokaddr,1)) nomem(); + tokaddr.len = 0; + + while (t > beginning) + switch((--t)->type) { + case TOKEN822_SEMI: + break; /*XXX*/ + case TOKEN822_COLON: + if (t >= beginning + 2) + if (t[-2].type == TOKEN822_COLON) + if (t[-1].type == TOKEN822_ATOM) + if (t[-1].slen == 7) + if (!byte_diff(t[-1].s,7,"include")) { + gotincl(); + t -= 2; + } + break; /*XXX*/ + case TOKEN822_RIGHT: + if (tokaddr.len) gotaddr(); + while ((t > beginning) && (t[-1].type != TOKEN822_LEFT)) + if (!token822_append(&tokaddr,--t)) nomem(); + gotaddr(); + if (t <= beginning) parseerr(); + --t; + while ((t > beginning) && ((t[-1].type == TOKEN822_COMMENT) || (t[-1].type == TOKEN822_ATOM) || (t[-1].type == TOKEN822_QUOTE) || (t[-1].type == TOKEN822_AT) || (t[-1].type == TOKEN822_DOT))) + --t; + wordok = 0; + continue; + case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: + if (!wordok) if (tokaddr.len) gotaddr(); + wordok = 0; + if (!token822_append(&tokaddr,t)) nomem(); + continue; + case TOKEN822_COMMENT: + /* comment is lexically a space; shouldn't affect wordok */ + break; + case TOKEN822_COMMA: + if (tokaddr.len) gotaddr(); + wordok = 1; + break; + default: + wordok = 1; + if (!token822_append(&tokaddr,t)) nomem(); + continue; + } + if (tokaddr.len) gotaddr(); +} + +char inbuf[1024]; +substdio ssin; +struct cdbmss cdbmss; +stralloc key = {0}; + +void doit() +{ + if (!instr.len) { + if (target.len) parseerr(); + return; + } + + if (!target.len) parseerr(); + + if (stralloc_starts(&target,"owner-")) { + if (!stralloc_copys(&key,"?")) nomem(); + if (!stralloc_catb(&key,target.s + 6,target.len - 6)) nomem(); + case_lowerb(key.s,key.len); + if (cdbmss_add(&cdbmss,key.s,key.len,fulltarget.s,fulltarget.len) == -1) writeerr(); + } + + if (!stralloc_copys(&key,":")) nomem(); + if (!stralloc_cat(&key,&target)) nomem(); + case_lowerb(key.s,key.len); + if (cdbmss_add(&cdbmss,key.s,key.len,instr.s,instr.len) == -1) writeerr(); +} + +void main() +{ + int fd; + + umask(033); + readcontrols(); + + fd = open_read("/etc/aliases"); + if (fd == -1) readerr(); + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf); + + fd = open_trunc("/etc/aliases.tmp"); + if (fd == -1) strerr_die2sys(111,FATAL,"unable to create /etc/aliases.tmp: "); + if (cdbmss_start(&cdbmss,fd) == -1) writeerr(); + + if (!stralloc_copys(&line,"")) nomem(); + + for (;;) { + if (getln(&ssin,&newline,&match,'\n') != 0) readerr(); + + if (match && (newline.s[0] == '\n')) continue; + + if (match && ((newline.s[0] == ' ') || (newline.s[0] == '\t'))) { + if (!stralloc_cat(&line,&newline)) nomem(); + continue; + } + + if (line.len) + if (line.s[0] != '#') { + if (!stralloc_copys(&target,"")) nomem(); + if (!stralloc_copys(&fulltarget,"")) nomem(); + if (!stralloc_copys(&instr,"")) nomem(); + parseline(); + doit(); + } + + if (!match) break; + if (!stralloc_copy(&line,&newline)) nomem(); + } + + if (cdbmss_finish(&cdbmss) == -1) writeerr(); + if (fsync(fd) == -1) writeerr(); + if (close(fd) == -1) writeerr(); /* NFS stupidity */ + + if (rename("/etc/aliases.tmp","/etc/aliases.cdb") == -1) + strerr_die2sys(111,FATAL,"unable to move /etc/aliases.tmp to /etc/aliases.cdb: "); + + _exit(0); +} diff --git a/newinclude.1 b/newinclude.1 new file mode 100644 index 0000000..b3ddf6e --- /dev/null +++ b/newinclude.1 @@ -0,0 +1,88 @@ +.TH newinclude 1 +.SH NAME +newinclude \- create a binary mailing list from an :include: file +.SH SYNOPSIS +.B newinclude +.I list +.SH DESCRIPTION +.B newinclude +reads a +sendmail-style +.B :include: +file, +.IR list , +and converts it into a binary format in +.I list\fB.bin +for use by +.BR fastforward . + +.B newinclude +first writes the mailing list to +.IR list\fB.tmp , +and then moves it to +.IR list\fB.bin . +If there is any problem creating +.IR list\fB.tmp , +.B newinclude +leaves +.I list\fB.bin +alone. + +.B newinclude +always creates +.I list\fB.bin +world-readable. + +.B COMPATIBILITY WARNING: +sendmail +reads +.I list +directly; +.B fastforward +needs +.IR list\fB.bin . +sendmail's strategy is a disaster if you save +.I list +to disk at the same moment that +sendmail +reads it; +the list will be truncated at a random spot, +perhaps in the middle of an address. +Furthermore, if the system crashes while you are writing +.IR list , +.I list +could be filled with all sorts of garbage. +.SH "LIST FORMAT" +.I list +may contain any number of lines; +each line may contain any number of addresses +or further +.B :include: +files. +See +.BR newaliases (1) +for details on the address format. +Any line in +.I file +beginning with # is ignored. + +.B COMPATIBILITY WARNING: +.B newinclude +does not support file or program deliveries in +.B :include: +files. +You can use the secure delivery mechanisms described in +.B dot-qmail(5) +instead. + +.B COMPATIBILITY WARNING: +Versions of +sendmail +before V8 did not allow comments in +.B :include: +files. +.SH "SEE ALSO" +fastforward(1), +newaliases(1), +setmaillist(1), +dot-qmail(5) diff --git a/newinclude.c b/newinclude.c new file mode 100644 index 0000000..ee1e0db --- /dev/null +++ b/newinclude.c @@ -0,0 +1,313 @@ +#include "substdio.h" +#include "strerr.h" +#include "stralloc.h" +#include "getln.h" +#include "open.h" +#include "readwrite.h" +#include "token822.h" +#include "control.h" +#include "auto_qmail.h" +#include "env.h" + +#define FATAL "newinclude: fatal: " + +void nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} +void usage() +{ + strerr_die1x(100,"newinclude: usage: newinclude list"); +} + + +char *fnlist; +substdio sslist; +char listbuf[1024]; + +stralloc bin = {0}; +#define fnbin bin.s +stralloc tmp = {0}; +#define fntmp tmp.s +substdio sstmp; +char tmpbuf[1024]; + +void readerr() +{ + strerr_die4sys(111,FATAL,"unable to read ",fnlist,": "); +} +void writeerr() +{ + strerr_die4sys(111,FATAL,"unable to write to ",fntmp,": "); +} + +void out(s,len) +char *s; +int len; +{ + if (substdio_put(&sstmp,s,len) == -1) writeerr(); +} + +void doincl(buf,len) +char *buf; +int len; +{ + if (!len) + strerr_die2x(111,FATAL,"empty :include: filenames not permitted"); + if (byte_chr(buf,len,'\n') != len) + strerr_die2x(111,FATAL,"newlines not permitted in :include: filenames"); + if (byte_chr(buf,len,'\0') != len) + strerr_die2x(111,FATAL,"NUL not permitted in :include: filenames"); + if ((buf[0] != '.') && (buf[0] != '/')) + out("./",2); + out(buf,len); + out("",1); +} + +void dorecip(buf,len) +char *buf; +int len; +{ + if (!len) + strerr_die2x(111,FATAL,"empty recipient addresses not permitted"); + if (byte_chr(buf,len,'\n') != len) + strerr_die2x(111,FATAL,"newlines not permitted in recipient addresses"); + if (byte_chr(buf,len,'\0') != len) + strerr_die2x(111,FATAL,"NUL not permitted in recipient addresses"); + if (len > 800) + strerr_die2x(111,FATAL,"addresses must be under 800 bytes"); + if ((buf[len - 1] == ' ') || (buf[len - 1] == '\t')) + strerr_die2x(111,FATAL,"spaces and tabs not permitted at ends of addresses"); + out("&",1); + out(buf,len); + out("",1); +} + + +void die_control() +{ + strerr_die2sys(111,FATAL,"unable to read controls: "); +} + +stralloc me = {0}; +stralloc defaulthost = {0}; +stralloc defaultdomain = {0}; +stralloc plusdomain = {0}; + +void readcontrols() +{ + int r; + int fddir; + char *x; + + fddir = open_read("."); + if (fddir == -1) + strerr_die2sys(111,FATAL,"unable to open current directory: "); + + if (chdir(auto_qmail) == -1) + strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": "); + + r = control_readline(&me,"control/me"); + if (r == -1) die_control(); + if (!r) if (!stralloc_copys(&me,"me")) nomem(); + + r = control_readline(&defaultdomain,"control/defaultdomain"); + if (r == -1) die_control(); + if (!r) if (!stralloc_copy(&defaultdomain,&me)) nomem(); + x = env_get("QMAILDEFAULTDOMAIN"); + if (x) if (!stralloc_copys(&defaultdomain,x)) nomem(); + + r = control_readline(&defaulthost,"control/defaulthost"); + if (r == -1) die_control(); + if (!r) if (!stralloc_copy(&defaulthost,&me)) nomem(); + x = env_get("QMAILDEFAULTHOST"); + if (x) if (!stralloc_copys(&defaulthost,x)) nomem(); + + r = control_readline(&plusdomain,"control/plusdomain"); + if (r == -1) die_control(); + if (!r) if (!stralloc_copy(&plusdomain,&me)) nomem(); + x = env_get("QMAILPLUSDOMAIN"); + if (x) if (!stralloc_copys(&plusdomain,x)) nomem(); + + if (fchdir(fddir) == -1) + strerr_die2sys(111,FATAL,"unable to set current directory: "); +} + +stralloc cbuf = {0}; +token822_alloc toks = {0}; +token822_alloc tokaddr = {0}; +stralloc address = {0}; + +void gotincl() +{ + token822_reverse(&tokaddr); + if (token822_unquote(&address,&tokaddr) != 1) nomem(); + tokaddr.len = 0; + doincl(address.s,address.len); +} + +void gotaddr() +{ + int i; + int j; + int flaghasat; + + token822_reverse(&tokaddr); + if (token822_unquote(&address,&tokaddr) != 1) nomem(); + + flaghasat = 0; + for (i = 0;i < tokaddr.len;++i) + if (tokaddr.t[i].type == TOKEN822_AT) + flaghasat = 1; + + tokaddr.len = 0; + + if (!address.len) return; + + if (!flaghasat) + if (address.s[0] == '/') { + if (!stralloc_0(&address)) nomem(); + strerr_die4x(111,FATAL,"file delivery ",address.s," not supported"); + } + if (!flaghasat) + if (address.s[0] == '|') { + if (!stralloc_0(&address)) nomem(); + strerr_die4x(111,FATAL,"program delivery ",address.s," not supported"); + } + + if (!flaghasat) { + if (!stralloc_cats(&address,"@")) nomem(); + if (!stralloc_cat(&address,&defaulthost)) nomem(); + } + if (address.s[address.len - 1] == '+') { + address.s[address.len - 1] = '.'; + if (!stralloc_cat(&address,&plusdomain)) nomem(); + } + j = 0; + for (i = 0;i < address.len;++i) if (address.s[i] == '@') j = i; + for (i = j;i < address.len;++i) if (address.s[i] == '.') break; + if (i == address.len) { + if (!stralloc_cats(&address,".")) nomem(); + if (!stralloc_cat(&address,&defaultdomain)) nomem(); + } + + dorecip(address.s,address.len); +} + + +stralloc line = {0}; +int match; + +void parseerr() +{ + if (!stralloc_0(&line)) nomem(); + strerr_die3x(111,FATAL,"unable to parse this line: ",line.s); +} + +void parseline() +{ + int wordok; + struct token822 *t; + struct token822 *beginning; + + switch(token822_parse(&toks,&line,&cbuf)) { + case -1: nomem(); + case 0: parseerr(); + } + + beginning = toks.t; + t = toks.t + toks.len; + wordok = 1; + + if (!token822_readyplus(&tokaddr,1)) nomem(); + tokaddr.len = 0; + + while (t > beginning) + switch((--t)->type) { + case TOKEN822_SEMI: + break; /*XXX*/ + case TOKEN822_COLON: + if (t >= beginning + 2) + if (t[-2].type == TOKEN822_COLON) + if (t[-1].type == TOKEN822_ATOM) + if (t[-1].slen == 7) + if (!byte_diff(t[-1].s,7,"include")) { + gotincl(); + t -= 2; + } + break; /*XXX*/ + case TOKEN822_RIGHT: + if (tokaddr.len) gotaddr(); + while ((t > beginning) && (t[-1].type != TOKEN822_LEFT)) + if (!token822_append(&tokaddr,--t)) nomem(); + gotaddr(); + if (t <= beginning) parseerr(); + --t; + while ((t > beginning) && ((t[-1].type == TOKEN822_COMMENT) || (t[-1].type == TOKEN822_ATOM) || (t[-1].type == TOKEN822_QUOTE) || (t[-1].type == TOKEN822_AT) || (t[-1].type == TOKEN822_DOT))) + --t; + wordok = 0; + continue; + case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: + if (!wordok) if (tokaddr.len) gotaddr(); + wordok = 0; + if (!token822_append(&tokaddr,t)) nomem(); + continue; + case TOKEN822_COMMENT: + /* comment is lexically a space; shouldn't affect wordok */ + break; + case TOKEN822_COMMA: + if (tokaddr.len) gotaddr(); + wordok = 1; + break; + default: + wordok = 1; + if (!token822_append(&tokaddr,t)) nomem(); + continue; + } + if (tokaddr.len) gotaddr(); +} + + +void main(argc,argv) +int argc; +char **argv; +{ + int fd; + + umask(033); + readcontrols(); + + fnlist = argv[1]; if (!fnlist) usage(); + + if (!stralloc_copys(&bin,fnlist)) nomem(); + if (!stralloc_cats(&bin,".bin")) nomem(); + if (!stralloc_0(&bin)) nomem(); + + if (!stralloc_copys(&tmp,fnlist)) nomem(); + if (!stralloc_cats(&tmp,".tmp")) nomem(); + if (!stralloc_0(&tmp)) nomem(); + + fd = open_read(fnlist); + if (fd == -1) readerr(); + substdio_fdbuf(&sslist,read,fd,listbuf,sizeof listbuf); + + fd = open_trunc(fntmp); + if (fd == -1) writeerr(); + substdio_fdbuf(&sstmp,write,fd,tmpbuf,sizeof tmpbuf); + + for (;;) { + if (getln(&sslist,&line,&match,'\n') == -1) readerr(); + if (!line.len) break; + if (line.s[0] != '#') parseline(); + if (!match) break; + } + + if (substdio_flush(&sstmp) == -1) writeerr(); + if (fsync(fd) == -1) writeerr(); + if (close(fd) == -1) writeerr(); /* NFS stupidity */ + + if (rename(fntmp,fnbin) == -1) + strerr_die6sys(111,FATAL,"unable to move ",fntmp," to ",fnbin,": "); + + _exit(0); +} 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_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/printforward.1 b/printforward.1 new file mode 100644 index 0000000..337b081 --- /dev/null +++ b/printforward.1 @@ -0,0 +1,16 @@ +.TH printforward 1 +.SH NAME +printforward \- print the instructions in a forwarding database +.SH SYNOPSIS +.B printforward +.SH DESCRIPTION +.B printforward +reads a forwarding database from its standard input +and prints all the forwarding instructions +in a format accepted by +.BR setforward . +.SH "SEE ALSO" +fastforward(1), +newaliases(1), +printmaillist(1), +setforward(1) diff --git a/printforward.c b/printforward.c new file mode 100644 index 0000000..f27cdd0 --- /dev/null +++ b/printforward.c @@ -0,0 +1,145 @@ +#include "substdio.h" +#include "subfd.h" +#include "strerr.h" +#include "stralloc.h" +#include "cdb.h" + +#define FATAL "printmaillist: fatal: " + +void badformat() +{ + strerr_die2x(100,FATAL,"bad database format"); +} +void nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +void getch(ch) +char *ch; +{ + int r; + r = substdio_get(subfdinsmall,ch,1); + if (r == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + if (r == 0) + badformat(); +} + +void putch(ch) +char *ch; +{ + if (substdio_put(subfdoutsmall,ch,1) == -1) + strerr_die2x(111,FATAL,"unable to write output: "); +} + +void print(buf) +char *buf; +{ + while (*buf) + putch(buf++); +} + +void printsafe(buf,len) +char *buf; +int len; +{ + char ch; + + while (len) { + ch = *buf; + if ((ch <= 32) || (ch == ',') || (ch == ':') || (ch == ';') || (ch == '\\') || (ch == '#')) + putch("\\"); + putch(&ch); + ++buf; + --len; + } +} + +stralloc key = {0}; +stralloc data = {0}; + +void main() +{ + uint32 eod; + uint32 pos; + uint32 klen; + uint32 dlen; + char buf[8]; + char ch; + int i; + int j; + + for (i = 0;i < 4;++i) getch(buf + i); + eod = cdb_unpack(buf); + + for (i = 4;i < 2048;++i) getch(&ch); + + pos = 2048; + while (pos < eod) { + if (eod - pos < 8) badformat(); + pos += 8; + for (i = 0;i < 8;++i) getch(buf + i); + klen = cdb_unpack(buf); + dlen = cdb_unpack(buf + 4); + + if (!stralloc_copys(&key,"")) nomem(); + if (eod - pos < klen) badformat(); + pos += klen; + while (klen) { + --klen; + getch(&ch); + if (!stralloc_append(&key,&ch)) nomem(); + } + + if (eod - pos < dlen) badformat(); + pos += dlen; + if (!stralloc_copys(&data,"")) nomem(); + while (dlen) { + --dlen; + getch(&ch); + if (!stralloc_append(&data,&ch)) nomem(); + } + + if (!key.len) badformat(); + if (key.s[0] == '?') { + printsafe(key.s + 1,key.len - 1); + print(": ?"); + printsafe(data.s,data.len); + print(";\n"); + } + else if (key.s[0] == ':') { + printsafe(key.s + 1,key.len - 1); + print(":\n"); + + i = 0; + for (j = 0;j < data.len;++j) + if (!data.s[j]) { + if ((data.s[i] == '.') || (data.s[i] == '/')) { + print(", "); + printsafe(data.s + i,j - i); + print("\n"); + } + else if ((data.s[i] == '|') || (data.s[i] == '!')) { + print(", "); + printsafe(data.s + i,j - i); + print("\n"); + } + else if ((data.s[i] == '&') && (j - i < 900)) { + print(", "); + printsafe(data.s + i,j - i); + print("\n"); + } + else badformat(); + i = j + 1; + } + if (i != j) badformat(); + print(";\n"); + } + else badformat(); + } + + if (substdio_flush(subfdoutsmall) == -1) + strerr_die2sys(111,FATAL,"unable to write output: "); + _exit(0); +} diff --git a/printmaillist.1 b/printmaillist.1 new file mode 100644 index 0000000..204b342 --- /dev/null +++ b/printmaillist.1 @@ -0,0 +1,15 @@ +.TH printmaillist 1 +.SH NAME +printmaillist \- print the contents of a binary mailing list +.SH SYNOPSIS +.B printmaillist +.SH DESCRIPTION +.B printmaillist +reads a binary mailing list from its standard input +and prints all the forwarding instructions +in a format accepted by +.BR setmaillist . +.SH "SEE ALSO" +newinclude(1), +printforward(1), +setmaillist(1) diff --git a/printmaillist.c b/printmaillist.c new file mode 100644 index 0000000..fa3b5a3 --- /dev/null +++ b/printmaillist.c @@ -0,0 +1,52 @@ +#include "substdio.h" +#include "subfd.h" +#include "strerr.h" +#include "stralloc.h" +#include "getln.h" + +#define FATAL "printmaillist: fatal: " + +void badformat() +{ + strerr_die2x(100,FATAL,"bad mailing list format"); +} + +stralloc line = {0}; +int match; + +void main() +{ + for (;;) { + if (getln(subfdinsmall,&line,&match,'\0') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + if (!match) { + if (line.len) + badformat(); + if (substdio_flush(subfdoutsmall) == -1) + strerr_die2sys(111,FATAL,"unable to write output: "); + _exit(0); + } + + if (line.s[str_chr(line.s,'\n')]) badformat(); + if (line.s[line.len - 1] == ' ') badformat(); + if (line.s[line.len - 1] == '\t') badformat(); + + if ((line.s[0] == '.') || (line.s[0] == '/')) { + if (substdio_puts(subfdoutsmall,line.s) == -1) + strerr_die2sys(111,FATAL,"unable to write output: "); + if (substdio_puts(subfdoutsmall,"\n") == -1) + strerr_die2sys(111,FATAL,"unable to write output: "); + continue; + } + if (line.s[0] == '&') { + if (line.len > 900) badformat(); + if (substdio_puts(subfdoutsmall,line.s) == -1) + strerr_die2sys(111,FATAL,"unable to write output: "); + if (substdio_puts(subfdoutsmall,"\n") == -1) + strerr_die2sys(111,FATAL,"unable to write output: "); + continue; + } + + badformat(); + } +} diff --git a/qmail.c b/qmail.c new file mode 100644 index 0000000..0fe0dfa --- /dev/null +++ b/qmail.c @@ -0,0 +1,125 @@ +#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(61); + 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); +} + +char *qmail_close(qq) +struct qmail *qq; +{ + int wstat; + int exitcode; + + 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 "Zqq waitpid surprise (#4.3.0)"; + if (wait_crashed(wstat)) + return "Zqq crashed (#4.3.0)"; + exitcode = wait_exitcode(wstat); + + switch(exitcode) { + case 115: /* compatibility */ + case 11: return "Denvelope address too long for qq (#5.1.3)"; + case 31: return "Dmail server permanently rejected message (#5.3.0)"; + case 51: return "Zqq out of memory (#4.3.0)"; + case 52: return "Zqq timeout (#4.3.0)"; + case 53: return "Zqq write error or disk full (#4.3.0)"; + case 0: if (!qq->flagerr) return ""; /* fall through */ + case 54: return "Zqq read error (#4.3.0)"; + case 55: return "Zqq unable to read configuration (#4.3.0)"; + case 56: return "Zqq trouble making network connection (#4.3.0)"; + case 61: return "Zqq trouble in home directory (#4.3.0)"; + case 63: + case 64: + case 65: + case 66: + case 62: return "Zqq trouble creating files in queue (#4.3.0)"; + case 71: return "Zmail server temporarily rejected message (#4.3.0)"; + case 72: return "Zconnection to mail server timed out (#4.4.1)"; + case 73: return "Zconnection to mail server rejected (#4.4.1)"; + case 74: return "Zcommunication with mail server failed (#4.4.2)"; + case 91: /* fall through */ + case 81: return "Zqq internal bug (#4.3.0)"; + case 120: return "Zunable to exec qq (#4.3.0)"; + default: + if ((exitcode >= 11) && (exitcode <= 40)) + return "Dqq permanent problem (#5.3.0)"; + return "Zqq temporary problem (#4.3.0)"; + } +} diff --git a/qmail.h b/qmail.h new file mode 100644 index 0000000..7fa13e2 --- /dev/null +++ b/qmail.h @@ -0,0 +1,24 @@ +#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 char *qmail_close(); +extern unsigned long qmail_qp(); + +#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_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_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/setforward.1 b/setforward.1 new file mode 100644 index 0000000..73cb8b5 --- /dev/null +++ b/setforward.1 @@ -0,0 +1,204 @@ +.TH setforward 1 +.SH NAME +setforward \- create a forwarding database +.SH SYNOPSIS +.B setforward +.I cdb +.I tmp +.SH DESCRIPTION +.B setforward +reads a table of forwarding instructions from its standard input. +It converts the table into a forwarding database. +The forwarding database can be used by +.BR fastforward . + +.B setforward +writes the forwarding database to +.IR tmp ; +it then moves +.I tmp +to +.IR cdb . +.I tmp +and +.I cdb +must be on the same filesystem. + +If there is a problem creating +.IR tmp , +.B setforward +complains and leaves +.I cdb +alone. + +The forwarding database format is portable across machines. +.SH "INSTRUCTION FORMAT" +A forwarding instruction contains a +.I target\fR, +a colon, a series of commands, and a semicolon. +Each command is a +.I recipient address\fR, +.I owner address\fR, +.I external mailing list\fR, +or +.I program\fR. +Commands are separated by commas. + +For example, + +.EX + root@yp.to: god@heaven.af.mil, staff@af.mil; +.EE + +says that mail for +.B root@yp.to +should be forwarded to the recipient addresses +.B god@heaven.af.mil +and +.BR staff@af.mil . + +When +.B setforward +sees # it ignores all text from # to the end of the line: + +.EX + # this is a comment +.EE + +.B setforward +ignores all other line endings, +so you can split a forwarding instruction across lines. +It also ignores spaces and tabs. +Exception: +you can put a space (or tab or comma or whatever) +into a target or command by putting a backslash in front of it. +(However, NUL bytes are not permitted anywhere.) +.SH "TARGETS" +When +.B fastforward +sees the incoming address +.IR user@host.dom , +it tries three targets: +.IR user@host.dom , +.IR @host.dom , +and +.IR user@ . +It obeys the commands for the first target that it finds. +Target names are interpreted without regard to case. + +All the commands for a single target must be listed in a single instruction. +Exception: an owner address can be listed in a separate instruction. +.SH "RECIPIENT ADDRESSES" +If a command begins with an ampersand, +.B setforward +takes the remaining bytes in the command as a recipient address: + +.EX + boss@yp.to: &god@heaven.af.mil; +.EE + +.B fastforward +sends each incoming mail message +to the recipient address. +The recipient address must include a fully qualified domain name. +It cannot be longer than 800 bytes. + +If a recipient address is itself a target in the forwarding table, +.B fastforward +will recursively handle the instructions for that target. +Note that +.I @host.dom +and +.I user@ +wildcards do not apply here; +they apply only to the incoming address. + +If a command begins with a letter or number, +.B setforward +takes the entire command as a recipient address: + +.EX + boss@yp.to: god@heaven.af.mil; +.EE +.SH "OWNER ADDRESSES" +If a command begins with a question mark, +.B setforward +takes the remaining bytes in the command as an owner address: + +.EX + sos@heaven.af.mil: ?owner-sos@heaven.af.mil; +.EE + +.B fastforward +uses that address as the envelope sender for forwarded mail, +so bounces will go back to that address. +(Normally, if a message is forwarded to a bad address, +it will bounce back to the original envelope sender.) +.SH "EXTERNAL MAILING LISTS" +If a command begins with a dot or slash, +.B setforward +takes the entire command as the name of a binary mailing list file created by +.BR setmaillist : + +.EX + sos@heaven.af.mil: /etc/lists/sos.bin; +.EE + +.B fastforward +will read and obey the commands in that file. +The file must be world-readable +and accessible to +.BR fastforward . +.SH "PROGRAMS" +If a command begins with a vertical bar or exclamation point, +.B setforward +takes the rest of the command as the name of a program to run: + +.EX + dew@: |dew-monitor; +.EE + +For a vertical bar, +.B fastforward +feeds the message +to that program. +An exclamation point works the same way except that +.B fastforward +inserts +.BR $UFLINE , +.BR $RPLINE , +and +.B $DTLINE +in front of the message. +.SH "DUPLICATES" +When +.B fastforward +is building the recipient list for a message, +it keeps track of the recipient addresses and external mailing lists +it has used. +If the same command shows up again, it skips it. +For example: + +.EX + everybody@yp.to: programmers@yp.to, testers@yp.to; + programmers@yp.to: joe@yp.to, bob@yp.to; + testers@yp.to: joe@yp.to, fred@yp.to; +.EE + +A message to +.B everybody@yp.to +will be sent to +.B joe@yp.to +only once. +(This also means that addresses in an internal forwarding loop +are discarded.) + +Exception: +If a target has an owner address, +commands for that target are considered different +from commands for ``outside'' targets. +.SH "SEE ALSO" +newaliases(1), +preline(1), +printforward(1), +setmaillist(1) diff --git a/setforward.c b/setforward.c new file mode 100644 index 0000000..42b72ae --- /dev/null +++ b/setforward.c @@ -0,0 +1,174 @@ +#include "substdio.h" +#include "subfd.h" +#include "strerr.h" +#include "stralloc.h" +#include "open.h" +#include "case.h" +#include "readwrite.h" +#include "cdbmss.h" + +#define FATAL "setforward: fatal: " + +void usage() +{ + strerr_die1x(100,"setforward: usage: setforward data.cdb data.tmp"); +} +void nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} +void missingsemicolon() +{ + strerr_die2x(100,FATAL,"final instruction must end with semicolon"); +} +void extracolon() +{ + strerr_die2x(100,FATAL,"double colons are not permitted"); +} +void extracomma() +{ + strerr_die2x(100,FATAL,"commas are not permitted before colons"); +} +void nulbyte() +{ + strerr_die2x(100,FATAL,"NUL bytes are not permitted"); +} +void longaddress() +{ + strerr_die2x(100,FATAL,"addresses over 800 bytes are not permitted"); +} + +char *fncdb; +char *fntmp; +int fd; +struct cdbmss cdbmss; +stralloc key = {0}; + +stralloc target = {0}; /* always initialized; no NUL */ +stralloc command = {0}; /* always initialized; no NUL */ +stralloc instr = {0}; /* always initialized */ + +int flagtarget = 0; +/* 0: reading target; command is empty; instr is empty */ +/* 1: target is complete; instr still has to be written; reading command */ + +void writeerr() +{ + strerr_die4sys(111,FATAL,"unable to write to ",fntmp,": "); +} + +void doit(prepend,data,datalen) +char *prepend; +char *data; +int datalen; +{ + if (!stralloc_copys(&key,prepend)) nomem(); + if (!stralloc_cat(&key,&target)) nomem(); + case_lowerb(key.s,key.len); + if (cdbmss_add(&cdbmss,key.s,key.len,data,datalen) == -1) + writeerr(); +} + +int getch(ch) +char *ch; +{ + int r; + + r = substdio_get(subfdinsmall,ch,1); + if (r == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + return r; +} + +void main(argc,argv) +int argc; +char **argv; +{ + char ch; + int r; + + if (!stralloc_copys(&target,"")) nomem(); + if (!stralloc_copys(&command,"")) nomem(); + if (!stralloc_copys(&instr,"")) nomem(); + + fncdb = argv[1]; if (!fncdb) usage(); + fntmp = argv[2]; if (!fntmp) usage(); + + fd = open_trunc(fntmp); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to create ",fntmp,": "); + + if (cdbmss_start(&cdbmss,fd) == -1) writeerr(); + + for (;;) { + if (!getch(&ch)) goto eof; + + if (ch == '#') { + while (ch != '\n') if (!getch(&ch)) goto eof; + continue; + } + + if (ch == ' ') continue; + if (ch == '\n') continue; + if (ch == '\t') continue; + + if (ch == ':') { + if (flagtarget) extracolon(); + flagtarget = 1; + continue; + } + + if ((ch == ',') || (ch == ';')) { + if (!flagtarget) extracomma(); + if (command.len) { + if (command.s[0] == '?') { + doit("?",command.s + 1,command.len - 1); + } + else if ((command.s[0] == '|') || (command.s[0] == '!')) { + if (!stralloc_cat(&instr,&command)) nomem(); + if (!stralloc_0(&instr)) nomem(); + } + else if ((command.s[0] == '.') || (command.s[0] == '/')) { + if (!stralloc_cat(&instr,&command)) nomem(); + if (!stralloc_0(&instr)) nomem(); + } + else { + if (command.len > 800) longaddress(); + if (command.s[0] != '&') + if (!stralloc_cats(&instr,"&")) nomem(); + if (!stralloc_cat(&instr,&command)) nomem(); + if (!stralloc_0(&instr)) nomem(); + } + } + + if (!stralloc_copys(&command,"")) nomem(); + + if (ch == ';') { + if (instr.len) + doit(":",instr.s,instr.len); + + if (!stralloc_copys(&target,"")) nomem(); + if (!stralloc_copys(&instr,"")) nomem(); + flagtarget = 0; + } + continue; + } + + if (ch == '\\') if (!getch(&ch)) goto eof; + if (ch == 0) nulbyte(); + if (!stralloc_append(flagtarget ? &command : &target,&ch)) nomem(); + } + + eof: + if (flagtarget || target.len) + missingsemicolon(); + + if (cdbmss_finish(&cdbmss) == -1) writeerr(); + if (fsync(fd) == -1) writeerr(); + if (close(fd) == -1) writeerr(); /* NFS stupidity */ + + if (rename(fntmp,fncdb) == -1) + strerr_die6sys(111,FATAL,"unable to move ",fntmp," to ",fncdb,": "); + + _exit(0); +} diff --git a/setmaillist.1 b/setmaillist.1 new file mode 100644 index 0000000..091a48a --- /dev/null +++ b/setmaillist.1 @@ -0,0 +1,72 @@ +.TH setmaillist 1 +.SH NAME +setmaillist \- create a binary mailing list +.SH SYNOPSIS +.B setmaillist +.I bin +.I tmp +.SH DESCRIPTION +.B setmaillist +reads a mailing list from its standard input. + +.B setmaillist +writes the mailing list in a binary format to +.IR tmp ; +it then moves +.I tmp +to +.IR bin . +.I tmp +and +.I bin +must be on the same filesystem. + +If there is a problem creating +.IR tmp , +.B setmaillist +complains and leaves +.I bin +alone. + +The binary mailing list format is portable across machines. + +.B setmaillist +always creates +.I bin +world-readable. +.SH "MAILING LIST FORMAT" +The mailing list read by +.B setmaillist +is a series of lines. +NUL bytes are not allowed. + +If a line begins with a dot or slash, +.B setmaillist +takes the entire line as an include file name. + +If a line begins with an ampersand, +.B setmaillist +takes the rest of the line as a recipient address. +If a line begins with a letter or number, +.B setmaillist +takes the entire line as a recipient address. +Each recipient address must include a fully qualified domain name. +Recipient addresses longer than 800 bytes are not allowed. + +.B setmaillist +ignores blank lines +and lines beginning with #. +It also ignores spaces and tabs at the ends of lines. + +For example, + +.EX + god@heaven.af.mil + djb@silverton.berkeley.edu +.EE + +is a mailing list with two addresses. +.SH "SEE ALSO" +setforward(1), +newinclude(1), +printmaillist(1) diff --git a/setmaillist.c b/setmaillist.c new file mode 100644 index 0000000..44f0240 --- /dev/null +++ b/setmaillist.c @@ -0,0 +1,94 @@ +#include "substdio.h" +#include "subfd.h" +#include "strerr.h" +#include "stralloc.h" +#include "getln.h" +#include "open.h" +#include "readwrite.h" + +#define FATAL "setmaillist: fatal: " + +void usage() +{ + strerr_die1x(100,"setmaillist: usage: setmaillist list.bin list.tmp"); +} + +stralloc line = {0}; +int match; + +char *fnbin; +char *fntmp; +int fd; +substdio ss; +char buf[1024]; + +void writeerr() +{ + strerr_die4sys(111,FATAL,"unable to write to ",fntmp,": "); +} + +void out(s,len) +char *s; +int len; +{ + if (substdio_put(&ss,s,len) == -1) writeerr(); +} + +void main(argc,argv) +int argc; +char **argv; +{ + umask(033); + + fnbin = argv[1]; if (!fnbin) usage(); + fntmp = argv[2]; if (!fntmp) usage(); + + fd = open_trunc(fntmp); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to create ",fntmp,": "); + + substdio_fdbuf(&ss,write,fd,buf,sizeof buf); + + do { + if (getln(subfdinsmall,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + + while (line.len) { + if (line.s[line.len - 1] != '\n') + if (line.s[line.len - 1] != ' ') + if (line.s[line.len - 1] != '\t') + break; + --line.len; + } + + if (byte_chr(line.s,line.len,'\0') != line.len) + strerr_die2x(111,FATAL,"NUL in input"); + + if (line.len) + if (line.s[0] != '#') { + if ((line.s[0] == '.') || (line.s[0] == '/')) { + out(line.s,line.len); + out("",1); + } + else { + if (line.len > 800) + strerr_die2x(111,FATAL,"addresses must be under 800 bytes"); + if (line.s[0] != '&') + out("&",1); + out(line.s,line.len); + out("",1); + } + } + + } + while (match); + + if (substdio_flush(&ss) == -1) writeerr(); + if (fsync(fd) == -1) writeerr(); + if (close(fd) == -1) writeerr(); /* NFS stupidity */ + + if (rename(fntmp,fnbin) == -1) + strerr_die6sys(111,FATAL,"unable to move ",fntmp," to ",fnbin,": "); + + _exit(0); +} diff --git a/sgetopt.c b/sgetopt.c new file mode 100644 index 0000000..a8bffc0 --- /dev/null +++ b/sgetopt.c @@ -0,0 +1,54 @@ +/* sgetopt.c, sgetopt.h: (yet another) improved getopt clone, outer layer +D. J. Bernstein, djb@pobox.com. +Depends on subgetopt.h, substdio.h, subfd.h. +No system requirements. +19970208: Cleanups. +931201: Baseline. +No known patent problems. + +Documentation in sgetopt.3. +*/ + +#include "substdio.h" +#include "subfd.h" +#define SGETOPTNOSHORT +#include "sgetopt.h" +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define getopt sgetoptmine +#define optind subgetoptind +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname + +int opterr = 1; +char *optprogname = 0; + +int getopt(argc,argv,opts) +int argc; +char **argv; +char *opts; +{ + int c; + char *s; + + if (!optprogname) { + optprogname = *argv; + if (!optprogname) optprogname = ""; + for (s = optprogname;*s;++s) if (*s == '/') optprogname = s + 1; + } + c = subgetopt(argc,argv,opts); + if (opterr) + if (c == '?') { + char chp[2]; chp[0] = optproblem; chp[1] = '\n'; + substdio_puts(subfderr,optprogname); + if (argv[optind] && (optind < argc)) + substdio_puts(subfderr,": illegal option -- "); + else + substdio_puts(subfderr,": option requires an argument -- "); + substdio_put(subfderr,chp,2); + substdio_flush(subfderr); + } + return c; +} diff --git a/sgetopt.h b/sgetopt.h new file mode 100644 index 0000000..5f89127 --- /dev/null +++ b/sgetopt.h @@ -0,0 +1,21 @@ +#ifndef SGETOPT_H +#define SGETOPT_H + +#ifndef SGETOPTNOSHORT +#define getopt sgetoptmine +#define optarg subgetoptarg +#define optind subgetoptind +#define optpos subgetoptpos +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname +#define opteof subgetoptdone +#endif + +#include "subgetopt.h" + +extern int sgetoptmine(); +extern int sgetopterr; +extern char *sgetoptprogname; + +#endif diff --git a/sig.h b/sig.h new file mode 100644 index 0000000..9c3a28c --- /dev/null +++ b/sig.h @@ -0,0 +1,43 @@ +#ifndef SIG_H +#define SIG_H + +extern void sig_catch(); +extern void sig_block(); +extern void sig_unblock(); +extern void sig_blocknone(); +extern void sig_pause(); + +extern void sig_dfl(); + +extern void sig_miscignore(); +extern void sig_bugcatch(); + +extern void sig_pipeignore(); +extern void sig_pipedefault(); + +extern void sig_contblock(); +extern void sig_contunblock(); +extern void sig_contcatch(); +extern void sig_contdefault(); + +extern void sig_termblock(); +extern void sig_termunblock(); +extern void sig_termcatch(); +extern void sig_termdefault(); + +extern void sig_alarmblock(); +extern void sig_alarmunblock(); +extern void sig_alarmcatch(); +extern void sig_alarmdefault(); + +extern void sig_childblock(); +extern void sig_childunblock(); +extern void sig_childcatch(); +extern void sig_childdefault(); + +extern void sig_hangupblock(); +extern void sig_hangupunblock(); +extern void sig_hangupcatch(); +extern void sig_hangupdefault(); + +#endif diff --git a/sig_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/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_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/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_arts.c b/stralloc_arts.c new file mode 100644 index 0000000..1ccb5a4 --- /dev/null +++ b/stralloc_arts.c @@ -0,0 +1,12 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_starts(sa,s) +stralloc *sa; +char *s; +{ + int len; + len = str_len(s); + return (sa->len >= len) && byte_equal(s,len,sa->s); +} diff --git a/stralloc_cat.c b/stralloc_cat.c new file mode 100644 index 0000000..efbb112 --- /dev/null +++ b/stralloc_cat.c @@ -0,0 +1,9 @@ +#include "byte.h" +#include "stralloc.h" + +int stralloc_cat(sato,safrom) +stralloc *sato; +stralloc *safrom; +{ + return stralloc_catb(sato,safrom->s,safrom->len); +} diff --git a/stralloc_catb.c b/stralloc_catb.c new file mode 100644 index 0000000..67dbcc0 --- /dev/null +++ b/stralloc_catb.c @@ -0,0 +1,15 @@ +#include "stralloc.h" +#include "byte.h" + +int stralloc_catb(sa,s,n) +stralloc *sa; +char *s; +unsigned int n; +{ + if (!sa->s) return stralloc_copyb(sa,s,n); + if (!stralloc_readyplus(sa,n + 1)) return 0; + byte_copy(sa->s + sa->len,n,s); + sa->len += n; + sa->s[sa->len] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_cats.c b/stralloc_cats.c new file mode 100644 index 0000000..d300286 --- /dev/null +++ b/stralloc_cats.c @@ -0,0 +1,10 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_cats(sa,s) +stralloc *sa; +char *s; +{ + return stralloc_catb(sa,s,str_len(s)); +} diff --git a/stralloc_copy.c b/stralloc_copy.c new file mode 100644 index 0000000..652aed6 --- /dev/null +++ b/stralloc_copy.c @@ -0,0 +1,9 @@ +#include "byte.h" +#include "stralloc.h" + +int stralloc_copy(sato,safrom) +stralloc *sato; +stralloc *safrom; +{ + return stralloc_copyb(sato,safrom->s,safrom->len); +} diff --git a/stralloc_eady.c b/stralloc_eady.c new file mode 100644 index 0000000..3a31f4b --- /dev/null +++ b/stralloc_eady.c @@ -0,0 +1,6 @@ +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready) +GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus) diff --git a/stralloc_opyb.c b/stralloc_opyb.c new file mode 100644 index 0000000..ac258b3 --- /dev/null +++ b/stralloc_opyb.c @@ -0,0 +1,14 @@ +#include "stralloc.h" +#include "byte.h" + +int stralloc_copyb(sa,s,n) +stralloc *sa; +char *s; +unsigned int n; +{ + if (!stralloc_ready(sa,n + 1)) return 0; + byte_copy(sa->s,n,s); + sa->len = n; + sa->s[n] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_opys.c b/stralloc_opys.c new file mode 100644 index 0000000..fdd7807 --- /dev/null +++ b/stralloc_opys.c @@ -0,0 +1,10 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_copys(sa,s) +stralloc *sa; +char *s; +{ + return stralloc_copyb(sa,s,str_len(s)); +} diff --git a/stralloc_pend.c b/stralloc_pend.c new file mode 100644 index 0000000..a3443b8 --- /dev/null +++ b/stralloc_pend.c @@ -0,0 +1,5 @@ +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append) diff --git a/strerr.h b/strerr.h new file mode 100644 index 0000000..d18e833 --- /dev/null +++ b/strerr.h @@ -0,0 +1,80 @@ +#ifndef STRERR_H +#define STRERR_H + +struct strerr + { + struct strerr *who; + char *x; + char *y; + char *z; + } +; + +extern struct strerr strerr_sys; +extern void strerr_sysinit(); + +extern char *strerr(); +extern void strerr_warn(); +extern void strerr_die(); + +#define STRERR(r,se,a) \ +{ se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; } + +#define STRERR_SYS(r,se,a) \ +{ se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; } +#define STRERR_SYS3(r,se,a,b,c) \ +{ se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; } + +#define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se)) +#define strerr_warn5(x1,x2,x3,x4,x5,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se)) +#define strerr_warn4(x1,x2,x3,x4,se) \ +strerr_warn((x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_warn3(x1,x2,x3,se) \ +strerr_warn((x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_warn2(x1,x2,se) \ +strerr_warn((x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_warn1(x1,se) \ +strerr_warn((x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) + +#define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se)) +#define strerr_die5(e,x1,x2,x3,x4,x5,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se)) +#define strerr_die4(e,x1,x2,x3,x4,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_die3(e,x1,x2,x3,se) \ +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_die2(e,x1,x2,se) \ +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) +#define strerr_die1(e,x1,se) \ +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se)) + +#define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys) +#define strerr_die5sys(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,&strerr_sys) +#define strerr_die4sys(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,&strerr_sys) +#define strerr_die3sys(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,&strerr_sys) +#define strerr_die2sys(e,x1,x2) \ +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys) +#define strerr_die1sys(e,x1) \ +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys) + +#define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) 0) +#define strerr_die5x(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) 0) +#define strerr_die4x(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) 0) +#define strerr_die3x(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) +#define strerr_die2x(e,x1,x2) \ +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) +#define strerr_die1x(e,x1) \ +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0) + +#endif diff --git a/strerr_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/strset.c b/strset.c new file mode 100644 index 0000000..9fb0cbd --- /dev/null +++ b/strset.c @@ -0,0 +1,130 @@ +#include "strset.h" +#include "str.h" +#include "byte.h" + +uint32 strset_hash(s) +char *s; +{ + unsigned char ch; + uint32 h; + h = 5381; + while (ch = *s) + { + h = ((h << 5) + h) ^ ch; + ++s; + } + return h; +} + +int strset_init(set) +strset *set; +{ + int h; + set->mask = 15; + set->n = 0; + set->a = 10; + + set->first = (int *) alloc(sizeof(int) * (set->mask + 1)); + if (!set->first) return 0; + set->p = (strset_list *) alloc(sizeof(strset_list) * set->a); + if (!set->p) { alloc_free(set->first); return 0; } + set->x = (char **) alloc(sizeof(char *) * set->a); + if (!set->x) { alloc_free(set->p); alloc_free(set->first); return 0; } + + for (h = 0;h <= set->mask;++h) set->first[h] = -1; + + return 1; +} + +char *strset_in(set,s) +strset *set; +char *s; +{ + uint32 h; + strset_list *sl; + int i; + char *xi; + + h = strset_hash(s); + i = set->first[h & set->mask]; + while (i >= 0) + { + sl = set->p + i; + if (sl->h == h) + { + xi = set->x[i]; + if (!str_diff(xi,s)) return xi; + } + i = sl->next; + } + return 0; +} + +int strset_add(set,s) +strset *set; +char *s; +{ + uint32 h; + int n; + strset_list *sl; + + n = set->n; + + if (n == set->a) + { + int newa; + strset_list *newp; + char **newx; + + newa = n + 10 + (n >> 3); + newp = (strset_list *) alloc(sizeof(strset_list) * newa); + if (!newp) return 0; + newx = (char **) alloc(sizeof(char *) * newa); + if (!newx) { alloc_free(newp); return 0; } + + byte_copy(newp,sizeof(strset_list) * n,set->p); + byte_copy(newx,sizeof(char *) * n,set->x); + alloc_free(set->p); + alloc_free(set->x); + set->p = newp; + set->x = newx; + set->a = newa; + + if (n + n + n > set->mask) + { + int newmask; + int *newfirst; + int i; + uint32 h; + + newmask = set->mask + set->mask + 1; + newfirst = (int *) alloc(sizeof(int) * (newmask + 1)); + if (!newfirst) return 0; + + for (h = 0;h <= newmask;++h) newfirst[h] = -1; + + for (i = 0;i < n;++i) + { + sl = set->p + i; + h = sl->h & newmask; + sl->next = newfirst[h]; + newfirst[h] = i; + } + + alloc_free(set->first); + set->first = newfirst; + set->mask = newmask; + } + } + + h = strset_hash(s); + + sl = set->p + n; + sl->h = h; + h &= set->mask; + sl->next = set->first[h]; + set->first[h] = n; + set->x[n] = s; + set->n = n + 1; + return 1; +} diff --git a/strset.h b/strset.h new file mode 100644 index 0000000..3af0759 --- /dev/null +++ b/strset.h @@ -0,0 +1,29 @@ +#ifndef STRSET_H +#define STRSET_H + +#include "uint32.h" + +typedef struct strset_list + { + uint32 h; + int next; + } +strset_list; + +typedef struct + { + int mask; /* mask + 1 is power of 2, size of hash table */ + int n; /* number of entries used in list and x */ + int a; /* number of entries allocated in list and x */ + int *first; /* first[h] is front of hash list h */ + strset_list *p; /* p[i].next is next; p[i].h is hash of x[i] */ + char **x; /* x[i] is entry i */ + } +strset; + +extern uint32 strset_hash(); +extern int strset_init(); +extern char *strset_in(); +extern int strset_add(); + +#endif diff --git a/subfd.h b/subfd.h new file mode 100644 index 0000000..bcb2e1e --- /dev/null +++ b/subfd.h @@ -0,0 +1,15 @@ +#ifndef SUBFD_H +#define SUBFD_H + +#include "substdio.h" + +extern substdio *subfdin; +extern substdio *subfdinsmall; +extern substdio *subfdout; +extern substdio *subfdoutsmall; +extern substdio *subfderr; + +extern int subfd_read(); +extern int subfd_readsmall(); + +#endif diff --git a/subfderr.c b/subfderr.c new file mode 100644 index 0000000..011ab0f --- /dev/null +++ b/subfderr.c @@ -0,0 +1,7 @@ +#include "readwrite.h" +#include "substdio.h" +#include "subfd.h" + +char subfd_errbuf[256]; +static substdio it = SUBSTDIO_FDBUF(write,2,subfd_errbuf,256); +substdio *subfderr = ⁢ diff --git a/subfdins.c b/subfdins.c new file mode 100644 index 0000000..36983ac --- /dev/null +++ b/subfdins.c @@ -0,0 +1,13 @@ +#include "readwrite.h" +#include "substdio.h" +#include "subfd.h" + +int subfd_readsmall(fd,buf,len) int fd; char *buf; int len; +{ + if (substdio_flush(subfdoutsmall) == -1) return -1; + return read(fd,buf,len); +} + +char subfd_inbufsmall[256]; +static substdio it = SUBSTDIO_FDBUF(subfd_readsmall,0,subfd_inbufsmall,256); +substdio *subfdinsmall = ⁢ diff --git a/subfdouts.c b/subfdouts.c new file mode 100644 index 0000000..5be356d --- /dev/null +++ b/subfdouts.c @@ -0,0 +1,7 @@ +#include "readwrite.h" +#include "substdio.h" +#include "subfd.h" + +char subfd_outbufsmall[256]; +static substdio it = SUBSTDIO_FDBUF(write,1,subfd_outbufsmall,256); +substdio *subfdoutsmall = ⁢ diff --git a/subgetopt.c b/subgetopt.c new file mode 100644 index 0000000..dacf376 --- /dev/null +++ b/subgetopt.c @@ -0,0 +1,79 @@ +/* subgetopt.c, subgetopt.h: (yet another) improved getopt clone, inner layer +D. J. Bernstein, djb@pobox.com. +No dependencies. +No system requirements. +19970228: Cleanups. +931129: Adapted from getopt.c. +No known patent problems. + +Documentation in subgetopt.3. +*/ + +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define sgopt subgetopt +#define optind subgetoptind +#define optpos subgetoptpos +#define optarg subgetoptarg +#define optproblem subgetoptproblem +#define optdone subgetoptdone + +int optind = 1; +int optpos = 0; +char *optarg = 0; +int optproblem = 0; +int optdone = SUBGETOPTDONE; + +int sgopt(argc,argv,opts) +int argc; +char **argv; +char *opts; +{ + int c; + char *s; + + optarg = 0; + if (!argv || (optind >= argc) || !argv[optind]) return optdone; + if (optpos && !argv[optind][optpos]) { + ++optind; + optpos = 0; + if ((optind >= argc) || !argv[optind]) return optdone; + } + if (!optpos) { + if (argv[optind][0] != '-') return optdone; + ++optpos; + c = argv[optind][1]; + if ((c == '-') || (c == 0)) { + if (c) ++optind; + optpos = 0; + return optdone; + } + /* otherwise c is reassigned below */ + } + c = argv[optind][optpos]; + ++optpos; + s = opts; + while (*s) { + if (c == *s) { + if (s[1] == ':') { + optarg = argv[optind] + optpos; + ++optind; + optpos = 0; + if (!*optarg) { + optarg = argv[optind]; + if ((optind >= argc) || !optarg) { /* argument past end */ + optproblem = c; + return '?'; + } + ++optind; + } + } + return c; + } + ++s; + if (*s == ':') ++s; + } + optproblem = c; + return '?'; +} diff --git a/subgetopt.h b/subgetopt.h new file mode 100644 index 0000000..d26c62a --- /dev/null +++ b/subgetopt.h @@ -0,0 +1,24 @@ +#ifndef SUBGETOPT_H +#define SUBGETOPT_H + +#ifndef SUBGETOPTNOSHORT +#define sgopt subgetopt +#define sgoptarg subgetoptarg +#define sgoptind subgetoptind +#define sgoptpos subgetoptpos +#define sgoptproblem subgetoptproblem +#define sgoptprogname subgetoptprogname +#define sgoptdone subgetoptdone +#endif + +#define SUBGETOPTDONE -1 + +extern int subgetopt(); +extern char *subgetoptarg; +extern int subgetoptind; +extern int subgetoptpos; +extern int subgetoptproblem; +extern char *subgetoptprogname; +extern int subgetoptdone; + +#endif diff --git a/substdi.c b/substdi.c new file mode 100644 index 0000000..42407a1 --- /dev/null +++ b/substdi.c @@ -0,0 +1,91 @@ +#include "substdio.h" +#include "byte.h" +#include "error.h" + +static int oneread(op,fd,buf,len) +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int r; + + for (;;) { + r = op(fd,buf,len); + if (r == -1) if (errno == error_intr) continue; + return r; + } +} + +static int getthis(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int r; + register int q; + + r = s->p; + q = r - len; + if (q > 0) { r = len; s->p = q; } else s->p = 0; + byte_copy(buf,r,s->x + s->n); + s->n += r; + return r; +} + +int substdio_feed(s) +register substdio *s; +{ + register int r; + register int q; + + if (s->p) return s->p; + q = s->n; + r = oneread(s->op,s->fd,s->x,q); + if (r <= 0) return r; + s->p = r; + q -= r; + s->n = q; + if (q > 0) /* damn, gotta shift */ byte_copyr(s->x + q,r,s->x); + return r; +} + +int substdio_bget(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int r; + + if (s->p > 0) return getthis(s,buf,len); + r = s->n; if (r <= len) return oneread(s->op,s->fd,buf,r); + r = substdio_feed(s); if (r <= 0) return r; + return getthis(s,buf,len); +} + +int substdio_get(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int r; + + if (s->p > 0) return getthis(s,buf,len); + if (s->n <= len) return oneread(s->op,s->fd,buf,len); + r = substdio_feed(s); if (r <= 0) return r; + return getthis(s,buf,len); +} + +char *substdio_peek(s) +register substdio *s; +{ + return s->x + s->n; +} + +void substdio_seek(s,len) +register substdio *s; +register int len; +{ + s->n += len; + s->p -= len; +} diff --git a/substdio.c b/substdio.c new file mode 100644 index 0000000..d03dff2 --- /dev/null +++ b/substdio.c @@ -0,0 +1,15 @@ +#include "substdio.h" + +void substdio_fdbuf(s,op,fd,buf,len) +register substdio *s; +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + s->x = buf; + s->fd = fd; + s->op = op; + s->p = 0; + s->n = len; +} diff --git a/substdio.h b/substdio.h new file mode 100644 index 0000000..c3f7f7d --- /dev/null +++ b/substdio.h @@ -0,0 +1,47 @@ +#ifndef SUBSTDIO_H +#define SUBSTDIO_H + +typedef struct substdio { + char *x; + int p; + int n; + int fd; + int (*op)(); +} substdio; + +#define SUBSTDIO_FDBUF(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } + +extern void substdio_fdbuf(); + +extern int substdio_flush(); +extern int substdio_put(); +extern int substdio_bput(); +extern int substdio_putflush(); +extern int substdio_puts(); +extern int substdio_bputs(); +extern int substdio_putsflush(); + +extern int substdio_get(); +extern int substdio_bget(); +extern int substdio_feed(); + +extern char *substdio_peek(); +extern void substdio_seek(); + +#define substdio_fileno(s) ((s)->fd) + +#define SUBSTDIO_INSIZE 8192 +#define SUBSTDIO_OUTSIZE 8192 + +#define substdio_PEEK(s) ( (s)->x + (s)->n ) +#define substdio_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) + +#define substdio_BPUTC(s,c) \ + ( ((s)->n != (s)->p) \ + ? ( (s)->x[(s)->p++] = (c), 0 ) \ + : substdio_bput((s),&(c),1) \ + ) + +extern int substdio_copy(); + +#endif diff --git a/substdio_copy.c b/substdio_copy.c new file mode 100644 index 0000000..71cf200 --- /dev/null +++ b/substdio_copy.c @@ -0,0 +1,18 @@ +#include "substdio.h" + +int substdio_copy(ssout,ssin) +register substdio *ssout; +register substdio *ssin; +{ + register int n; + register char *x; + + for (;;) { + n = substdio_feed(ssin); + if (n < 0) return -2; + if (!n) return 0; + x = substdio_PEEK(ssin); + if (substdio_put(ssout,x,n) == -1) return -3; + substdio_SEEK(ssin,n); + } +} diff --git a/substdo.c b/substdo.c new file mode 100644 index 0000000..fb616f7 --- /dev/null +++ b/substdo.c @@ -0,0 +1,108 @@ +#include "substdio.h" +#include "str.h" +#include "byte.h" +#include "error.h" + +static int allwrite(op,fd,buf,len) +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +int substdio_flush(s) +register substdio *s; +{ + register int p; + + p = s->p; + if (!p) return 0; + s->p = 0; + return allwrite(s->op,s->fd,s->x,p); +} + +int substdio_bput(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int n; + + while (len > (n = s->n - s->p)) { + byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n; + if (substdio_flush(s) == -1) return -1; + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int substdio_put(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + register int n; + + n = s->n; + if (len > n - s->p) { + if (substdio_flush(s) == -1) return -1; + /* now s->p == 0 */ + if (n < SUBSTDIO_OUTSIZE) n = SUBSTDIO_OUTSIZE; + while (len > s->n) { + if (n > len) n = len; + if (allwrite(s->op,s->fd,buf,n) == -1) return -1; + buf += n; + len -= n; + } + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int substdio_putflush(s,buf,len) +register substdio *s; +register char *buf; +register int len; +{ + if (substdio_flush(s) == -1) return -1; + return allwrite(s->op,s->fd,buf,len); +} + +int substdio_bputs(s,buf) +register substdio *s; +register char *buf; +{ + return substdio_bput(s,buf,str_len(buf)); +} + +int substdio_puts(s,buf) +register substdio *s; +register char *buf; +{ + return substdio_put(s,buf,str_len(buf)); +} + +int substdio_putsflush(s,buf) +register substdio *s; +register char *buf; +{ + return substdio_putflush(s,buf,str_len(buf)); +} diff --git a/token822.c b/token822.c new file mode 100644 index 0000000..48a4388 --- /dev/null +++ b/token822.c @@ -0,0 +1,513 @@ +#include "stralloc.h" +#include "alloc.h" +#include "str.h" +#include "token822.h" +#include "gen_allocdefs.h" + +static struct token822 comma = { TOKEN822_COMMA }; + +void token822_reverse(ta) +token822_alloc *ta; +{ + int i; + int n; + struct token822 temp; + + n = ta->len - 1; + for (i = 0;i + i < n;++i) + { + temp = ta->t[i]; + ta->t[i] = ta->t[n - i]; + ta->t[n - i] = temp; + } +} + +GEN_ALLOC_ready(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_ready) +GEN_ALLOC_readyplus(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus) +GEN_ALLOC_append(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus,token822_append) + +static int needspace(t1,t2) +int t1; +int t2; +{ + if (!t1) return 0; + if (t1 == TOKEN822_COLON) return 1; + if (t1 == TOKEN822_COMMA) return 1; + if (t2 == TOKEN822_LEFT) return 1; + switch(t1) + { + case TOKEN822_ATOM: case TOKEN822_LITERAL: + case TOKEN822_QUOTE: case TOKEN822_COMMENT: + switch(t2) + { + case TOKEN822_ATOM: case TOKEN822_LITERAL: + case TOKEN822_QUOTE: case TOKEN822_COMMENT: + return 1; + } + } + return 0; +} + +static int atomok(ch) +char ch; +{ + switch(ch) + { + case ' ': case '\t': case '\r': case '\n': + case '(': case '[': case '"': + case '<': case '>': case ';': case ':': + case '@': case ',': case '.': + return 0; + } + return 1; +} + +static void atomcheck(t) +struct token822 *t; +{ + int i; + char ch; + for (i = 0;i < t->slen;++i) + { + ch = t->s[i]; + if ((ch < 32) || (ch > 126) || (ch == ')') || (ch == ']') || (ch == '\\')) + { + t->type = TOKEN822_QUOTE; + return; + } + } +} + +int token822_unparse(sa,ta,linelen) +stralloc *sa; +token822_alloc *ta; +unsigned int linelen; +{ + struct token822 *t; + int len; + int ch; + int i; + int j; + int lasttype; + int newtype; + char *s; + char *lineb; + char *linee; + + len = 0; + lasttype = 0; + for (i = 0;i < ta->len;++i) + { + t = ta->t + i; + newtype = t->type; + if (needspace(lasttype,newtype)) + ++len; + lasttype = newtype; + switch(newtype) + { + case TOKEN822_COMMA: + len += 3; break; + case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT: case TOKEN822_RIGHT: + case TOKEN822_SEMI: case TOKEN822_COLON: + ++len; break; + case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT: + if (t->type != TOKEN822_ATOM) len += 2; + for (j = 0;j < t->slen;++j) + switch(ch = t->s[j]) + { + case '"': case '[': case ']': case '(': case ')': + case '\\': case '\r': case '\n': ++len; + default: ++len; + } + break; + } + } + len += 2; + + if (!stralloc_ready(sa,len)) + return -1; + + s = sa->s; + lineb = s; + linee = 0; + + lasttype = 0; + for (i = 0;i < ta->len;++i) + { + t = ta->t + i; + newtype = t->type; + if (needspace(lasttype,newtype)) + *s++ = ' '; + lasttype = newtype; + switch(newtype) + { + case TOKEN822_COMMA: + *s++ = ','; +#define NSUW \ + s[0] = '\n'; s[1] = ' '; \ + if (linee && (!linelen || (s - lineb <= linelen))) \ + { while (linee < s) { linee[0] = linee[2]; ++linee; } linee -= 2; } \ + else { if (linee) lineb = linee + 1; linee = s; s += 2; } + NSUW + break; + case TOKEN822_AT: *s++ = '@'; break; + case TOKEN822_DOT: *s++ = '.'; break; + case TOKEN822_LEFT: *s++ = '<'; break; + case TOKEN822_RIGHT: *s++ = '>'; break; + case TOKEN822_SEMI: *s++ = ';'; break; + case TOKEN822_COLON: *s++ = ':'; break; + case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT: + if (t->type == TOKEN822_QUOTE) *s++ = '"'; + if (t->type == TOKEN822_LITERAL) *s++ = '['; + if (t->type == TOKEN822_COMMENT) *s++ = '('; + for (j = 0;j < t->slen;++j) + switch(ch = t->s[j]) + { + case '"': case '[': case ']': case '(': case ')': + case '\\': case '\r': case '\n': *s++ = '\\'; + default: *s++ = ch; + } + if (t->type == TOKEN822_QUOTE) *s++ = '"'; + if (t->type == TOKEN822_LITERAL) *s++ = ']'; + if (t->type == TOKEN822_COMMENT) *s++ = ')'; + break; + } + } + NSUW + --s; + sa->len = s - sa->s; + return 1; +} + +int token822_unquote(sa,ta) +stralloc *sa; +token822_alloc *ta; +{ + struct token822 *t; + int len; + int i; + int j; + char *s; + + len = 0; + for (i = 0;i < ta->len;++i) + { + t = ta->t + i; + switch(t->type) + { + case TOKEN822_COMMA: case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT: + case TOKEN822_RIGHT: case TOKEN822_SEMI: case TOKEN822_COLON: + ++len; break; + case TOKEN822_LITERAL: + len += 2; + case TOKEN822_ATOM: case TOKEN822_QUOTE: + len += t->slen; + } + } + + if (!stralloc_ready(sa,len)) + return -1; + + s = sa->s; + + for (i = 0;i < ta->len;++i) + { + t = ta->t + i; + switch(t->type) + { + case TOKEN822_COMMA: *s++ = ','; break; + case TOKEN822_AT: *s++ = '@'; break; + case TOKEN822_DOT: *s++ = '.'; break; + case TOKEN822_LEFT: *s++ = '<'; break; + case TOKEN822_RIGHT: *s++ = '>'; break; + case TOKEN822_SEMI: *s++ = ';'; break; + case TOKEN822_COLON: *s++ = ':'; break; + case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: + if (t->type == TOKEN822_LITERAL) *s++ = '['; + for (j = 0;j < t->slen;++j) + *s++ = t->s[j]; + if (t->type == TOKEN822_LITERAL) *s++ = ']'; + break; + case TOKEN822_COMMENT: break; + } + } + sa->len = s - sa->s; + return 1; +} + +int token822_parse(ta,sa,buf) +token822_alloc *ta; +stralloc *sa; +stralloc *buf; +{ + int i; + int salen; + int level; + struct token822 *t; + int numtoks; + int numchars; + char *cbuf; + + salen = sa->len; + + numchars = 0; + numtoks = 0; + for (i = 0;i < salen;++i) + switch(sa->s[i]) + { + case '.': case ',': case '@': case '<': case '>': case ':': case ';': + ++numtoks; break; + case ' ': case '\t': case '\r': case '\n': break; + case ')': case ']': return 0; + /* other control chars and non-ASCII chars are also bad, in theory */ + case '(': + level = 1; + while (level) + { + if (++i >= salen) return 0; + switch(sa->s[i]) + { + case '(': ++level; break; + case ')': --level; break; + case '\\': if (++i >= salen) return 0; + default: ++numchars; + } + } + ++numtoks; + break; + case '"': + level = 1; + while (level) + { + if (++i >= salen) return 0; + switch(sa->s[i]) + { + case '"': --level; break; + case '\\': if (++i >= salen) return 0; + default: ++numchars; + } + } + ++numtoks; + break; + case '[': + level = 1; + while (level) + { + if (++i >= salen) return 0; + switch(sa->s[i]) + { + case ']': --level; break; + case '\\': if (++i >= salen) return 0; + default: ++numchars; + } + } + ++numtoks; + break; + default: + do + { + if (sa->s[i] == '\\') if (++i >= salen) break; + ++numchars; + if (++i >= salen) + break; + } + while (atomok(sa->s[i])); + --i; + ++numtoks; + } + + if (!token822_ready(ta,numtoks)) + return -1; + if (!stralloc_ready(buf,numchars)) + return -1; + cbuf = buf->s; + ta->len = numtoks; + + t = ta->t; + for (i = 0;i < salen;++i) + switch(sa->s[i]) + { + case '.': t->type = TOKEN822_DOT; ++t; break; + case ',': t->type = TOKEN822_COMMA; ++t; break; + case '@': t->type = TOKEN822_AT; ++t; break; + case '<': t->type = TOKEN822_LEFT; ++t; break; + case '>': t->type = TOKEN822_RIGHT; ++t; break; + case ':': t->type = TOKEN822_COLON; ++t; break; + case ';': t->type = TOKEN822_SEMI; ++t; break; + case ' ': case '\t': case '\r': case '\n': break; + case '(': + t->type = TOKEN822_COMMENT; t->s = cbuf; t->slen = 0; + level = 1; + while (level) + { + ++i; /* assert: < salen */ + switch(sa->s[i]) + { + case '(': ++level; break; + case ')': --level; break; + case '\\': ++i; /* assert: < salen */ + default: *cbuf++ = sa->s[i]; ++t->slen; + } + } + ++t; + break; + case '"': + t->type = TOKEN822_QUOTE; t->s = cbuf; t->slen = 0; + level = 1; + while (level) + { + ++i; /* assert: < salen */ + switch(sa->s[i]) + { + case '"': --level; break; + case '\\': ++i; /* assert: < salen */ + default: *cbuf++ = sa->s[i]; ++t->slen; + } + } + ++t; + break; + case '[': + t->type = TOKEN822_LITERAL; t->s = cbuf; t->slen = 0; + level = 1; + while (level) + { + ++i; /* assert: < salen */ + switch(sa->s[i]) + { + case ']': --level; break; + case '\\': ++i; /* assert: < salen */ + default: *cbuf++ = sa->s[i]; ++t->slen; + } + } + ++t; + break; + default: + t->type = TOKEN822_ATOM; t->s = cbuf; t->slen = 0; + do + { + if (sa->s[i] == '\\') if (++i >= salen) break; + *cbuf++ = sa->s[i]; ++t->slen; + if (++i >= salen) + break; + } + while (atomok(sa->s[i])); + atomcheck(t); + --i; + ++t; + } + return 1; +} + +static int gotaddr(taout,taaddr,callback) +token822_alloc *taout; +token822_alloc *taaddr; +int (*callback)(); +{ + int i; + + if (callback(taaddr) != 1) + return 0; + + if (!token822_readyplus(taout,taaddr->len)) + return 0; + + for (i = 0;i < taaddr->len;++i) + taout->t[taout->len++] = taaddr->t[i]; + + taaddr->len = 0; + return 1; +} + +int token822_addrlist(taout,taaddr,ta,callback) +token822_alloc *taout; +token822_alloc *taaddr; +token822_alloc *ta; +int (*callback)(); +{ + struct token822 *t; + struct token822 *beginning; + int ingroup; + int wordok; + + taout->len = 0; + taaddr->len = 0; + + if (!token822_readyplus(taout,1)) return -1; + if (!token822_readyplus(taaddr,1)) return -1; + + ingroup = 0; + wordok = 1; + + beginning = ta->t + 2; + t = ta->t + ta->len - 1; + + /* rfc 822 address lists are easy to parse from right to left */ + +#define FLUSH if (taaddr->len) if (!gotaddr(taout,taaddr,callback)) return -1; +#define FLUSHCOMMA if (taaddr->len) { \ +if (!gotaddr(taout,taaddr,callback)) return -1; \ +if (!token822_append(taout,&comma)) return -1; } +#define ADDRLEFT if (!token822_append(taaddr,t--)) return -1; +#define OUTLEFT if (!token822_append(taout,t--)) return -1; + + while (t >= beginning) + { + switch(t->type) + { + case TOKEN822_SEMI: + FLUSHCOMMA + if (ingroup) return 0; + ingroup = 1; + wordok = 1; + break; + case TOKEN822_COLON: + FLUSH + if (!ingroup) return 0; + ingroup = 0; + while ((t >= beginning) && (t->type != TOKEN822_COMMA)) + OUTLEFT + if (t >= beginning) + OUTLEFT + wordok = 1; + continue; + case TOKEN822_RIGHT: + FLUSHCOMMA + OUTLEFT + while ((t >= beginning) && (t->type != TOKEN822_LEFT)) + ADDRLEFT + /* important to use address here even if it's empty: <> */ + if (!gotaddr(taout,taaddr,callback)) return -1; + if (t < beginning) return 0; + OUTLEFT + while ((t >= beginning) && ((t->type == TOKEN822_COMMENT) || (t->type == TOKEN822_ATOM) || (t->type == TOKEN822_QUOTE) || (t->type == TOKEN822_AT) || (t->type == TOKEN822_DOT))) + OUTLEFT + wordok = 0; + continue; + case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: + if (!wordok) + FLUSHCOMMA + wordok = 0; + ADDRLEFT + continue; + case TOKEN822_COMMENT: + /* comment is lexically a space; shouldn't affect wordok */ + break; + case TOKEN822_COMMA: + FLUSH + wordok = 1; + break; + default: + wordok = 1; + ADDRLEFT + continue; + } + OUTLEFT + } + FLUSH + ++t; + while (t > ta->t) + if (!token822_append(taout,--t)) return -1; + + token822_reverse(taout); + return 1; +} diff --git a/token822.h b/token822.h new file mode 100644 index 0000000..9ca35cf --- /dev/null +++ b/token822.h @@ -0,0 +1,37 @@ +#ifndef TOKEN822_H +#define TOKEN822_H + +struct token822 + { + int type; + char *s; + int slen; + } +; + +#include "gen_alloc.h" +GEN_ALLOC_typedef(token822_alloc,struct token822,t,len,a) + +extern int token822_parse(); +extern int token822_addrlist(); +extern int token822_unquote(); +extern int token822_unparse(); +extern void token822_free(); +extern void token822_reverse(); +extern int token822_ready(); +extern int token822_readyplus(); +extern int token822_append(); + +#define TOKEN822_ATOM 1 +#define TOKEN822_QUOTE 2 +#define TOKEN822_LITERAL 3 +#define TOKEN822_COMMENT 4 +#define TOKEN822_LEFT 5 +#define TOKEN822_RIGHT 6 +#define TOKEN822_AT 7 +#define TOKEN822_COMMA 8 +#define TOKEN822_SEMI 9 +#define TOKEN822_COLON 10 +#define TOKEN822_DOT 11 + +#endif diff --git a/trycpp.c b/trycpp.c new file mode 100644 index 0000000..d7d83ad --- /dev/null +++ b/trycpp.c @@ -0,0 +1,7 @@ +void main() +{ +#ifdef NeXT + printf("nextstep\n"); exit(0); +#endif + printf("unknown\n"); exit(0); +} diff --git a/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.h1 b/uint32.h1 new file mode 100644 index 0000000..6599aa0 --- /dev/null +++ b/uint32.h1 @@ -0,0 +1,6 @@ +#ifndef UINT32_H +#define UINT32_H + +typedef unsigned int uint32; + +#endif diff --git a/uint32.h2 b/uint32.h2 new file mode 100644 index 0000000..716430d --- /dev/null +++ b/uint32.h2 @@ -0,0 +1,6 @@ +#ifndef UINT32_H +#define UINT32_H + +typedef unsigned long uint32; + +#endif diff --git a/wait.h b/wait.h new file mode 100644 index 0000000..cdb77c3 --- /dev/null +++ b/wait.h @@ -0,0 +1,14 @@ +#ifndef WAIT_H +#define WAIT_H + +extern int wait_pid(); +extern int wait_nohang(); +extern int wait_stop(); +extern int wait_stopnohang(); + +#define wait_crashed(w) ((w) & 127) +#define wait_exitcode(w) ((w) >> 8) +#define wait_stopsig(w) ((w) >> 8) +#define wait_stopped(w) (((w) & 127) == 127) + +#endif diff --git a/wait_pid.c b/wait_pid.c new file mode 100644 index 0000000..d7a7e84 --- /dev/null +++ b/wait_pid.c @@ -0,0 +1,39 @@ +#include +#include +#include "error.h" +#include "haswaitp.h" + +#ifdef HASWAITPID + +int wait_pid(wstat,pid) int *wstat; int pid; +{ + int r; + + do + r = waitpid(pid,wstat,0); + while ((r == -1) && (errno == error_intr)); + return r; +} + +#else + +/* XXX untested */ +/* XXX breaks down with more than two children */ +static int oldpid = 0; +static int oldwstat; /* defined if(oldpid) */ + +int wait_pid(wstat,pid) int *wstat; int pid; +{ + int r; + + if (pid == oldpid) { *wstat = oldwstat; oldpid = 0; return pid; } + + do { + r = wait(wstat); + if ((r != pid) && (r != -1)) { oldwstat = *wstat; oldpid = r; continue; } + } + while ((r == -1) && (errno == error_intr)); + return r; +} + +#endif diff --git a/warn-auto.sh b/warn-auto.sh new file mode 100644 index 0000000..36d2313 --- /dev/null +++ b/warn-auto.sh @@ -0,0 +1,2 @@ +#!/bin/sh +# WARNING: This file was auto-generated. Do not edit! -- 2.11.0