safecat-1.13/0000775000076400007640000000000010416316304012412 5ustar budneybudneysafecat-1.13/CHANGES0000664000076400007640000000345210416225046013413 0ustar budneybudney20060409 Added Vadim Druzhin's RPM buildroot support. TNX also Charlie Brady. 20040816 Added support for Linux LARGEFILE flag to safecat.c. 20040816 Fixed typo in error message. TNX Daniel Biddle. 20040816 Changed errno test to include errno.h by default. 20030701 Release 1.11 20030701 Fixed overflow in tempfile creation. TNX Toby Betts, Guy Garnett 20030603 Release 1.10 20030603 Fixed errors in conf-version. TNX Peter van Dijk 20030603 Fixed glibc-induced incompatibility. TNX all who bugged me on this 20030603 Fixed omission of version string for "ident". TNX Peter van Dijk 20030603 Changed filename to conform to updated maildir spec. 20020523 Release 1.9 20020523 Fixed test for type of uint64. 20020523 Cast added so timestamps aren't munged on Solaris. TNX Paul Grayson 20010414 Release 1.8 20010414 Install dirs now created if needed. TNX Peter Bray 20010414 Added RPM spec 20010409 Release 1.6 20010409 Removed obsolete autoconf files from distribution. TNX Peter Bray 20010409 Fixed path in stat() of temporary file. TNX Erik Sjolund 20010212 Release 1.5 20010212 BUGFIX: Failed to delete tempfile if link() fails. TNX Peter van Dijk 20010212 BUGFIX: Tempfile not deleted if writefile() fails. TNX Peter van Dijk 20010212 Safecat tries 5 times now, like docs say, not 6. TNX Peter van Dijk 20010212 Added comment to manpage about procmail's maildir support 20010212 Added CHANGES file 20001121 Release 1.4 20001121 Deleted bogosities like unused "configure" script 20000721 Release 1.3 20000721 I/O buffers 1K->.5K; same performance, smaller footprint 20000721 Cleaned out unused variables left over from previous versions 20000229 Release 1.2 20000229 Changed license from GPL to BSD with the "Don't Bother Dan" clause 20000229 Completely rewrote safecat to use code borrowed from Dan Bernstein 19991209 Release 1.1 safecat-1.13/COPYING0000664000076400007640000000624507242121565013462 0ustar budneybudneyAll original content is Copyright (c) 2000 and 2001, Len Budney. All rights reserved. Copying permissions for safecat comes in two parts: 1. All code written by me is offered under the BSD license. See below for the text of the BSD license. Original content is clearly marked with a copyright notice and my name. 2. Other components of the package, like the programs ``setup'' and ``instcheck'', were derived from code written by Dan Bernstein. Dan has not specified the licensing of (some of) his code; some of his code he has released into the public domain. My best understanding of Dan's position, based on what he has written on the subject, is that he doesn't mind if people borrow his code--as long as you make supporting that code your own problem. In particular, the following considerations apply: a. If you have problems with safecat or anything in this distribution, contact me about it--. Do NOT bother Dan. b. If you think you've found problems in Dan's code, as contained in this distribution, contact me first anyway. If I can verify that the bug exists and isn't mine, I'll pass the info on to Dan. Do NOT bother Dan. c. If you want to use Dan's code for your own projects, then 1) you do so at your own risk, and 2) you should assume full responsibility for maintenance of your project, including borrowed code, just as I'm doing here for safecat. The BSD License states: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by the University of California, Berkeley and its contributors. - Neither name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. safecat-1.13/INSTALL0000664000076400007640000000141507056643244013460 0ustar budneybudney Installation Instructions for Safecat 1. Get the Distribution Source code distributions of safecat are available for download via http from the author's homepage . 2. Unpack the Source Code To unpack the safecat distribution, cd to the directory containing the gzipped archive and type: gunzip -c safecat-VERSION.tar.gz | tar xvf - 3. Build and Install safecat make make setup check The final step must be performed as root, unless you are installing safecat in your home directory or some other location owned by you. You can specify the destination directories for safecat program and manpage by editing the conf-* files; no other configuration should be necessary. safecat-1.13/Makefile0000664000076400007640000002231110110253101014033 0ustar budneybudney# Makefile for safecat 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_no.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_home.c: \ auto-str conf-root ./auto-str auto_home `head -1 conf-root` > auto_home.c auto_home.o: \ compile auto_home.c ./compile auto_home.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 byte_zero.o: \ compile byte_zero.c byte.h ./compile byte_zero.c check: \ it instcheck ./instcheck clean: \ TARGETS rm -f `cat TARGETS` compile: \ make-compile warn-auto.sh systype conf-includes ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \ compile chmod 755 compile 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_no.h: \ tryerrno.c compile load error_no.h1 error_no.h2 ( ( ./compile tryerrno.c && ./load tryerrno && \ ./tryerrno ) >/dev/null 2>&1 \ && cat error_no.h1 || cat error_no.h2 ) > error_no.h rm -f tryerrno.o tryerrno error.o: \ compile error.c error_no.h ./compile error.c error_str.o: \ compile error_str.c error_no.h ./compile error_str.c fmt_uint64.o: \ compile fmt_uint64.c fmt.h uint64.h ./compile fmt_uint64.c hier.o: \ compile hier.c auto_home.h ./compile hier.c install: \ load install.o hier.o auto_home.o strerr.a substdio.a open.a error.a \ str.a ./load install hier.o auto_home.o strerr.a substdio.a \ open.a error.a str.a install.o: \ compile install.c substdio.h strerr.h error_no.h open.h readwrite.h \ exit.h buffer.h ./compile install.c instcheck: \ load instcheck.o hier.o auto_home.o strerr.a substdio.a error.a str.a ./load instcheck hier.o auto_home.o strerr.a substdio.a \ error.a str.a instcheck.o: \ compile instcheck.c strerr.h error_no.h readwrite.h exit.h ./compile instcheck.c it: \ maildir safecat man find-systype: \ find-systype.sh auto-ccld.sh cat auto-ccld.sh find-systype.sh > find-systype chmod 755 find-systype 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 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 hostname.o: \ compile hostname.c ./compile hostname.c load: \ make-load warn-auto.sh systype ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load chmod 755 load maildir: \ warn-auto.sh maildir.sh conf-root cat warn-auto.sh maildir.sh \ | sed s}HOME}"`head -1 conf-root`"}g \ > maildir chmod 755 maildir maildir.0: \ maildir.1 nroff -man maildir.1 > maildir.0 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 makelib: \ warn-auto.sh systype ( cat warn-auto.sh; \ echo 'main="$$1"; shift'; \ echo 'rm -f "$$main"'; \ echo 'ar cr "$$main" $${1+"$$@"}'; \ case "`cat systype`" in \ sunos-5.*) ;; \ unix_sv*) ;; \ irix64-*) ;; \ irix-*) ;; \ dgux-*) ;; \ hp-ux-*) ;; \ sco*) ;; \ *) echo 'ranlib "$$main"' ;; \ esac \ ) > makelib chmod 755 makelib man: \ safecat.0 maildir.0 open.a: \ makelib open_read.o open_trunc.o open_append.o ./makelib open.a open_read.o open_trunc.o open_append.o open_append.o: \ compile open_append.c open.h ./compile open_append.c 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 safecat: \ load safecat.o getln.a str.a stralloc.a strerr.a substdio.a alloc.o \ alloc_re.o byte_copy.o byte_cr.o envread.o error.o error_str.o fmt_uint64.o \ hostname.o sig.o stat_dir.o str_diffn.o str_len.o substdio_copy.o \ substdi.o substdio.o taia_fmtfrac.o taia_now.o taia_tai.o tempfile.o \ writefile.o ./load safecat getln.a str.a stralloc.a strerr.a substdio.a \ alloc.o alloc_re.o byte_copy.o byte_cr.o envread.o error.o \ error_str.o fmt_uint64.o hostname.o sig.o stat_dir.o str_diffn.o \ str_len.o substdi.o substdio.o substdio_copy.o taia_fmtfrac.o \ taia_now.o taia_tai.o tempfile.o writefile.o safecat.0: \ safecat.1 nroff -man safecat.1 > safecat.0 safecat.o: \ compile safecat.c uint32.h version.h sig.h tempfile.h stat_dir.h \ writefile.h ./compile safecat.c sig.o: \ compile sig.c hassgact.h ./compile sig.c setup: \ it install ./install stat_dir.o: \ compile stat_dir.c ./compile stat_dir.c str.a: \ makelib str_len.o byte_chr.o byte_diff.o byte_copy.o byte_cr.o \ byte_zero.o ./makelib str.a str_len.o byte_chr.o byte_diff.o \ byte_copy.o byte_cr.o byte_zero.o str_diffn.o: \ compile str_diffn.c str.h ./compile str_diffn.c str_len.o: \ compile str_len.c str.h ./compile str_len.c stralloc.a: \ makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \ stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \ stralloc_catb.o stralloc_arts.o stralloc_num.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_num.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_num.o: \ compile stralloc_num.c stralloc.h gen_alloc.h ./compile stralloc_num.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_no.h strerr.h ./compile strerr_sys.c subfderr.o: \ compile subfderr.c readwrite.h substdio.h subfd.h substdio.h ./compile subfderr.c subfdin.o: \ compile subfdin.c readwrite.h substdio.h subfd.h substdio.h ./compile subfdin.c subfdins.o: \ compile subfdins.c readwrite.h substdio.h subfd.h substdio.h ./compile subfdins.c subfdout.o: \ compile subfdout.c readwrite.h substdio.h subfd.h substdio.h ./compile subfdout.c subfdouts.o: \ compile subfdouts.c readwrite.h substdio.h subfd.h substdio.h ./compile subfdouts.c substdi.o: \ compile substdi.c substdio.h byte.h error_no.h ./compile substdi.c substdio.a: \ makelib substdio.o substdi.o substdo.o subfderr.o subfdout.o \ subfdouts.o subfdin.o subfdins.o substdio_copy.o ./makelib substdio.a substdio.o substdi.o substdo.o \ subfderr.o subfdout.o subfdouts.o subfdin.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_no.h ./compile substdo.c systype: \ find-systype trycpp.c ./find-systype > systype taia_fmtfrac.o: \ compile taia_fmtfrac.c taia.h tai.h uint64.h ./compile taia_fmtfrac.c taia_now.o: \ compile taia_now.c taia.h tai.h uint64.h ./compile taia_now.c taia_tai.o: \ compile taia_tai.c taia.h tai.h uint64.h ./compile taia_tai.c tempfile.o: \ compile tempfile.c ./compile tempfile.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 uint64.h: \ tryulong64.c compile load uint64.h1 uint64.h2 ( ( ./compile tryulong64.c && ./load tryulong64 && \ ./tryulong64 ) >/dev/null 2>&1 \ && cat uint64.h2 || cat uint64.h1 ) > uint64.h rm -f tryulong64.o tryulong64 version.h: \ conf-version @echo 'static const char *const version_string="$$Version:' \ `head -1 conf-version` 'built' `date +"%b %d, %Y"` at \ `date +"%H:%M"`'$$";' > version.h writefile.o: \ compile writefile.c ./compile writefile.c safecat-1.13/README0000664000076400007640000000433510110256710013272 0ustar budneybudney Safecat Len Budney February 29, 2000 1. Introduction safecat is an implementation of D. J. Bernstein's maildir algorithm. It can be used to write mail messages to a qmail-style maildir, or to write data to a "spool" directory reliably. There are no lockfiles with safecat, and nothing is left to chance. If safecat returns a successful exit status, then you can be (practically) 100% sure your data is safely committed to disk. Further, if data is written to a directory using safecat (or other implementations of the maildir algorithm), then every file in that directory is guaranteed to be complete. If safecat fails to write all of the data, there will be no file at all in the destination directory. Of course, you know that such a thing cannot be: between UNIX and the different hardware options available, a 100% guarantee is not possible. However, safecat takes every precaution possible in writing your data. 2. Getting safecat The source code for safecat may be downloaded from or from sunsite or one of its mirrors. To build and install safecat, follow the instructions in the included INSTALL file. To summarize: make make setup check 3. Copying safecat is offered under the terms of the BSD License. The included file COPYING is a copy of the license. 4. Caveats On some systems, handling an email larger than 2GB may cause safecat to fail silently. This is an OS bug; the correct behavior, if large files are not supported, is to return failure upon writing past the supported file size. On those systems that support the O_LARGEFILE flag, mainly Linux, you can turn on large file support by editing conf-cc. I recommend you look into a different tool, such as rsync, for processing files larger than 2GB. 5. Credits The maildir algorithm implemented in safecat was devised by Professor D. J. Bernstein, and is implemented in his qmail mailer. Other (approximate) implementations of the algorithm exist, in procmail, mutt, and the Emacs mailreader Mew, but to my knowledge this is the only standalone implementation, and the most complete implementation outside of qmail itself. safecat-1.13/TARGETS0000664000076400007640000000163410110253207013443 0ustar budneybudneyalloc.a alloc.o alloc_re.o auto-ccld.sh auto-str auto-str.o auto_home.c auto_home.o byte_chr.o byte_copy.o byte_cr.o byte_diff.o byte_zero.o compile error.a error.o error_str.o find-systype fmt_uint64.o getln.a getln.o getln2.o hassgact.h hier.o hostname.o install install.o instcheck instcheck.o load make-compile make-load makelib open.a open_append.o open_read.o open_trunc.o safecat safecat.o sig.o stat_dir.o str.a str_len.o stralloc.a stralloc_arts.o stralloc_cat.o stralloc_catb.o stralloc_cats.o stralloc_copy.o stralloc_eady.o stralloc_num.o stralloc_opyb.o stralloc_opys.o stralloc_pend.o strerr.a strerr_die.o strerr_sys.o subfderr.o subfdin.o subfdins.o subfdout.o subfdouts.o substdi.o substdio.a substdio.o substdio_copy.o substdo.o systype taia_fmtfrac.o taia_now.o taia_tai.o tempfile.o uint32.h version.h writefile.o maildir envread.o str_diffn.o uint64.h maildir.0 safecat.0 tryerrno.o tryerrno error_no.h safecat-1.13/alloc.30000664000076400007640000000167607056643244013616 0ustar budneybudney.TH alloc 3 .SH NAME alloc \- allocate memory .SH SYNTAX .B #include char *\fBalloc\fP(\fInew\fR); void \fBalloc_free\fP(\fIx\fR); void \fBalloc_re\fP(&\fIx\fR,\fIold\fR,\fInew\fR); char *\fIx\fR; .br unsigned int \fIold\fR; .br unsigned int \fInew\fR; .SH DESCRIPTION .B alloc allocates enough space from the heap for .I new bytes of data, adequately aligned for any data type. .I new may be 0. .B alloc returns a pointer to the space. If space is not available, .B alloc returns 0, setting .B errno appropriately. .B alloc_free returns space to the heap. .B alloc_re expands the space allocated to .I x from .I old bytes to .I new bytes. It allocates new space, copies .I old bytes from the old space to the new space, returns the old space to the heap, and changes .I x to point to the new space. It then returns 1. If space is not available, .B alloc_re returns 0, leaving the old space alone. .SH "SEE ALSO" sbrk(2), malloc(3), error(3) safecat-1.13/alloc.c0000664000076400007640000000150107056643244013661 0ustar budneybudney#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); } safecat-1.13/alloc.h0000664000076400007640000000020307056643244013664 0ustar budneybudney#ifndef ALLOC_H #define ALLOC_H extern /*@null@*//*@out@*/char *alloc(); extern void alloc_free(); extern int alloc_re(); #endif safecat-1.13/alloc_re.c0000664000076400007640000000032607056643244014353 0ustar budneybudney#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; } safecat-1.13/auto-str.c0000664000076400007640000000135207056643244014351 0ustar budneybudney#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); } safecat-1.13/auto_home.h0000664000076400007640000000011207056643244014551 0ustar budneybudney#ifndef AUTO_HOME_H #define AUTO_HOME_H extern char auto_home[]; #endif safecat-1.13/buffer.h0000664000076400007640000000246207056643244014054 0ustar budneybudney#ifndef BUFFER_H #define BUFFER_H typedef struct buffer { char *x; unsigned int p; unsigned int n; int fd; int (*op)(); } buffer; #define BUFFER_INIT(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } #define BUFFER_INSIZE 8192 #define BUFFER_OUTSIZE 8192 extern void buffer_init(buffer *,int (*)(),int,char *,unsigned int); extern int buffer_flush(buffer *); extern int buffer_put(buffer *,char *,unsigned int); extern int buffer_putalign(buffer *,char *,unsigned int); extern int buffer_putflush(buffer *,char *,unsigned int); extern int buffer_puts(buffer *,char *); extern int buffer_putsalign(buffer *,char *); extern int buffer_putsflush(buffer *,char *); #define buffer_PUTC(s,c) \ ( ((s)->n != (s)->p) \ ? ( (s)->x[(s)->p++] = (c), 0 ) \ : buffer_put((s),&(c),1) \ ) extern int buffer_get(buffer *,char *,unsigned int); extern int buffer_bget(buffer *,char *,unsigned int); extern int buffer_feed(buffer *); extern char *buffer_peek(buffer *); extern void buffer_seek(buffer *,unsigned int); #define buffer_PEEK(s) ( (s)->x + (s)->n ) #define buffer_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) extern int buffer_copy(buffer *,buffer *); extern buffer *buffer_0; extern buffer *buffer_0small; extern buffer *buffer_1; extern buffer *buffer_1small; extern buffer *buffer_2; #endif safecat-1.13/byte.h0000664000076400007640000000040107056643244013535 0ustar budneybudney#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 safecat-1.13/byte_chr.c0000664000076400007640000000060207056643244014367 0ustar budneybudney#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; } safecat-1.13/byte_copy.c0000664000076400007640000000045307056643244014571 0ustar budneybudney#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; } } safecat-1.13/byte_cr.c0000664000076400007640000000050407056643244014220 0ustar budneybudney#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; } } safecat-1.13/byte_diff.c0000664000076400007640000000070507056643244014527 0ustar budneybudney#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); } safecat-1.13/byte_zero.c0000664000076400007640000000034607056643244014577 0ustar budneybudney#include "byte.h" void byte_zero(s,n) char *s; register unsigned int n; { for (;;) { if (!n) break; *s++ = 0; --n; if (!n) break; *s++ = 0; --n; if (!n) break; *s++ = 0; --n; if (!n) break; *s++ = 0; --n; } } safecat-1.13/conf-cc0000664000076400007640000000030310110255653013641 0ustar budneybudneycc -O2 This will be used to compile .c files. Add any needed flags here; for example, if you want support for files larger than 2GB on Linux systems, you might add "-D_LARGEFILE64_SOURCE" here. safecat-1.13/conf-includes0000664000076400007640000000000007056643244015070 0ustar budneybudneysafecat-1.13/conf-ld0000664000076400007640000000007607056643244013676 0ustar budneybudneycc -s This will be used to link .o files into an executable. safecat-1.13/conf-root0000664000076400007640000000026307056643244014260 0ustar budneybudney/usr/local The first line of this file gives the top-level directory for installation. Files will be installed in the appropriate subdirectories; bin, lib, include, man and etc. safecat-1.13/conf-version0000664000076400007640000000037510416222004014743 0ustar budneybudney1.13 The revision number of the software being distributed. This should not need to be changed by the user. If you modify this code, and then use it for any purpose, you SHOULD change this number; maybe to something like "old-version + 1"."your name". safecat-1.13/env.30000664000076400007640000000113007056643244013275 0ustar budneybudney.TH env 3 .SH NAME env \- manage the environment .SH SYNTAX .B #include char **\fBenviron\fP; char *\fBenv_get\fP(\fIname\fR); .br char *\fBenv_pick\fP(); char *\fIname\fR; .SH DESCRIPTION The environment, .BR environ , is a 0-terminated array of 0-terminated strings, called environment variables. Each environment variable is of the form .IR name\fB=\fIvalue . .B env_get returns the value of the first variable whose name is .IR name , or 0 if there is no such variable. .B env_pick returns any variable in the environment, or 0 if the environment is empty. .SH "SEE ALSO" environ(7) safecat-1.13/env.h0000664000076400007640000000044007056643244013365 0ustar budneybudney#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 safecat-1.13/envread.c0000664000076400007640000000067107242115636014216 0ustar budneybudney#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; } safecat-1.13/error.c0000664000076400007640000000167207056643244013731 0ustar budneybudney#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 int error_nodevice = #ifdef ENXIO ENXIO; #else -14; #endif safecat-1.13/safecat-buildroot.patch0000644000076400007640000000046310416221361017041 0ustar budneybudney--- Makefile.orig Tue Aug 17 04:50:09 2004 +++ Makefile Wed Sep 22 16:48:02 2004 @@ -31,7 +31,7 @@ auto_home.c: \ auto-str conf-root - ./auto-str auto_home `head -1 conf-root` > auto_home.c + ./auto-str auto_home $(RPM_BUILD_ROOT)`head -1 conf-root` > auto_home.c auto_home.o: \ compile auto_home.c safecat-1.13/error_str.c0000664000076400007640000001265107056643244014620 0ustar budneybudney#include #include "error.h" #define X(e,s) if (i == e) return s; char *error_str(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") X(error_nodevice,"device not configured") #ifdef ESRCH X(ESRCH,"no such process") #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"; } safecat-1.13/exit.h0000664000076400007640000000007407056643244013551 0ustar budneybudney#ifndef EXIT_H #define EXIT_H extern void _exit(); #endif safecat-1.13/find-systype.sh0000664000076400007640000000650307056643244015424 0ustar budneybudney# 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]' safecat-1.13/fmt.h0000664000076400007640000000130607474313600013357 0ustar budneybudney#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_uint64(); 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 safecat-1.13/fmt_uint64.c0000664000076400007640000000050707474314471014574 0ustar budneybudney#include "fmt.h" #include "uint64.h" unsigned int fmt_uint64(s,u) register char *s; register uint64 u; { register unsigned int len; register uint64 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; } safecat-1.13/gen_alloc.h0000664000076400007640000000025507056643244014524 0ustar budneybudney#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 safecat-1.13/gen_allocdefs.h0000664000076400007640000000226207056643244015366 0ustar budneybudney#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 safecat-1.13/getln.30000664000076400007640000000126507056643244013627 0ustar budneybudney.TH getln 3 .SH NAME getln \- read one line of data .SH SYNTAX .B #include int \fBgetln\fP(&\fIss\fR,&\fIsa\fR,&\fImatch\fR,\fIsep\fR); substdio \fIss\fR; .br stralloc \fIsa\fR; .br int \fImatch\fR; .br int \fIsep\fR; .SH DESCRIPTION .B getln reads a line of characters, terminated by a .I sep character, from .IR ss . It returns the line in .I sa and sets .I match to 1. If .B getln sees end-of-input before it sees .IR sep , it returns the partial line in .I sa and sets .I match to 0. .B getln normally returns 0. If it runs out of memory, or encounters an error from .IR ss , it returns -1, setting .B errno appropriately. .SH "SEE ALSO" stralloc(3), substdio(3), getln2(3) safecat-1.13/getln.c0000664000076400007640000000057607056643244013713 0ustar budneybudney#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; } safecat-1.13/getln.h0000664000076400007640000000012207056643244013703 0ustar budneybudney#ifndef GETLN_H #define GETLN_H extern int getln(); extern int getln2(); #endif safecat-1.13/getln2.30000664000076400007640000000166707056643244013717 0ustar budneybudney.TH getln2 3 .SH NAME getln2 \- read one line of data .SH SYNTAX .B #include int \fBgetln2\fP(&\fIss\fR,&\fIsa\fR,&\fIcont\fR,&\fIclen\fR,\fIsep\fR); substdio \fIss\fR; .br stralloc \fIsa\fR; .br char *\fIcont\fR; .br unsigned int \fIclen\fR; .br int \fIsep\fR; .SH DESCRIPTION .B getln2 reads a line of characters, terminated by a .I sep character, from .IR ss . The line is returned in two pieces. The first piece is stored in .IR sa . The second piece is .IR cont , a pointer to .I clen characters inside the .I ss buffer. The second piece must be copied somewhere else before .I ss is used again. If .B getln2 sees end-of-input before it sees .IR sep , it sets .I clen to 0 and does not set .IR cont . It puts the partial line into .IR sa . .B getln2 normally returns 0. If it runs out of memory, or encounters an error from .IR ss , it returns -1, setting .B errno appropriately. .SH "SEE ALSO" stralloc(3), substdio(3), getln(3) safecat-1.13/getln2.c0000664000076400007640000000126007056643244013764 0ustar budneybudney#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); } } safecat-1.13/hier.c0000664000076400007640000000076507266030002013512 0ustar budneybudney#include "auto_home.h" void hier() { h(auto_home,-1,-1,02755); d(auto_home,"bin",-1,-1,02755); c(auto_home,"bin","safecat",-1,-1,0755); c(auto_home,"bin","maildir",-1,-1,0755); d(auto_home,"man",-1,-1,02755); d(auto_home,"man/man1",-1,-1,02755); d(auto_home,"man/cat1",-1,-1,02755); c(auto_home,"man/man1","safecat.1",-1,-1,0644); c(auto_home,"man/cat1","safecat.0",-1,-1,0644); c(auto_home,"man/man1","maildir.1",-1,-1,0644); c(auto_home,"man/cat1","maildir.0",-1,-1,0644); } safecat-1.13/hostname.c0000664000076400007640000000074707056643244014420 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ #include "hostname.h" #include "strerr.h" #include /* ****************************************************************** */ void get_hostname(char *hostnam, size_t len) { if(gethostname(hostnam, len) == 0) return; /* Fatal error if we can't read the hostname. */ strerr_die1sys(111, "safecat: fatal: can't determine hostname: "); } /* ****************************************************************** */ safecat-1.13/hostname.h0000664000076400007640000000030607056643244014414 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ /* Look up the name of the local host. */ #ifndef size_t #include #endif void get_hostname(char *hostnam, size_t len); safecat-1.13/install-sh0000775000076400007640000001272107020761630014424 0ustar budneybudney#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 safecat-1.13/install.c0000664000076400007640000001002307056643244014234 0ustar budneybudney#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 z(home,subdir,file,len,uid,gid,mode) char *home; char *subdir; char *file; int len; int uid; int gid; int mode; { int fdout; 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); while (len-- > 0) if (substdio_put(&ssout,"",1) == -1) strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); 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); } safecat-1.13/instcheck.c0000664000076400007640000000437007056643244014551 0ustar budneybudney#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 p(home,fifo,uid,gid,mode) char *home; char *fifo; int uid; int gid; int mode; { if (chdir(home) == -1) strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); perm("",home,"/",fifo,S_IFIFO,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 z(home,file,len,uid,gid,mode) char *home; char *file; int len; int uid; int gid; int mode; { if (chdir(home) == -1) strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); perm("",home,"/",file,S_IFREG,uid,gid,mode); } main() { hier(); _exit(0); } safecat-1.13/maildir.10000664000076400007640000000127207056643244014133 0ustar budneybudney.TH maildir 1 .SH "NAME" maildir \- safely write data to a qmail-style maildir .SH "SYNOPSIS" .B maildir .I dir .SH "INTRODUCTION" .I maildir is a shell script which invokes .IR safecat . It is equivalent to .I safecat .IR dir /tmp .IR dir /new. It saves a little typing for those who want to use qmail maildirs, which have a fixed structure. .IR safecat , on the other hand, allows the user to have one temporary directory for many spool directories. This is occasionally useful; some people don't like to multiply the number of places which need to be periodically cleaned up. Copyright (c) 2000, Len Budney. All rights reserved. .SH "SEE ALSO" safecat(1) mbox(5), qmail-local(8), maildir(5) safecat-1.13/maildir.sh0000664000076400007640000000014607056643244014404 0ustar budneybudney# Copyright (c) 2000, Len Budney. See COPYING for details. exec \ HOME/bin/safecat "$1"/tmp "$1"/new safecat-1.13/make-compile.sh0000664000076400007640000000007107056643244015323 0ustar budneybudneyecho exec "$CC" "`head -1 conf-includes`" -c '${1+"$@"}' safecat-1.13/make-load.sh0000664000076400007640000000011107056643244014605 0ustar budneybudneyecho 'main="$1"; shift' echo exec "$LD" '-o "$main" "$main".o ${1+"$@"}' safecat-1.13/open.h0000664000076400007640000000024307056643244013537 0ustar budneybudney#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 safecat-1.13/open_append.c0000664000076400007640000000023607056643244015063 0ustar budneybudney#include #include #include "open.h" int open_append(fn) char *fn; { return open(fn,O_WRONLY | O_NDELAY | O_APPEND | O_CREAT,0600); } safecat-1.13/open_read.c0000664000076400007640000000020207056643244014520 0ustar budneybudney#include #include #include "open.h" int open_read(fn) char *fn; { return open(fn,O_RDONLY | O_NDELAY); } safecat-1.13/open_trunc.c0000664000076400007640000000023407056643244014745 0ustar budneybudney#include #include #include "open.h" int open_trunc(fn) char *fn; { return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); } safecat-1.13/readwrite.h0000664000076400007640000000013007056643244014557 0ustar budneybudney#ifndef READWRITE_H #define READWRITE_H extern int read(); extern int write(); #endif safecat-1.13/safecat.10000664000076400007640000002556510110257436014120 0ustar budneybudney.TH safecat 1 .SH "NAME" safecat \- safely write data to a file .SH "SYNOPSIS" .B safecat .I tempdir .I destdir .SH "INTRODUCTION" .I safecat is a program which implements Professor Daniel Bernstein's .I maildir algorithm to copy .I stdin safely to a file in a specified directory. With .IR safecat , the user is offered two assurances. First, if .I safecat returns a successful exit status, then all data is guaranteed to be saved in the destination directory. Second, if a file exists in the destination directory, placed there by .IR safecat , then the file is guaranteed to be complete. When saving data with .IR safecat , the user specifies a destination directory, but not a file name. The file name is selected by .I safecat to ensure that no filename collisions occur, even if many .I safecat processes and other programs implementing the .I maildir algorithm are writing to the directory simultaneously. If particular filenames are desired, then the user should rename the file after .I safecat completes. In general, when spooling data with .IR safecat , a single, separate process should handle naming, collecting, and deleting these files. Examples of such a process are daemons, cron jobs, and mail readers. .SH "RELIABILITY ISSUES" A machine may crash while data is being written to disk. For many programs, including many mail delivery agents, this means that the data will be silently truncated. Using Professor Bernstein's .IR maildir algorithm, every file is guaranteed complete or nonexistent. Many people or programs may write data to a common "spool" directory. Systems like .I mh-mail store files using numeric names in a directory. Incautious writing to files can result in a collision, in which one write succeeds and the other appears to succeed but fails. Common strategies to resolve this problem involve creation of lock files or other synchronizing mechanisms, but such mechanisms are subject to failure. Anyone who has deleted $HOME/.netscape/lock in order to start netscape can attest to this. The .IR maildir algorithm is immune to this problem because it uses no locks at all. .SH "THE MAILDIR ALGORITHM" As described in maildir(5), .I safecat applies the .I maildir algorithm by writing data in six steps. First, it .B stat()s the two directories .I tempdir and .IR destdir , and exits unless both directories exist and are writable. Second, it .B stat()s the name .BR tempdir/\fItime.pid.host , where .I time is the number of seconds since the beginning of 1970 GMT, .I pid is the program's process ID, and .I host is the host name. Third, if .B stat() returned anything other than ENOENT, the program sleeps for two seconds, updates .IR time , and tries the .B stat() again, a limited number of times. Fourth, the program creates .BR tempdir/\fItime.pid.host . Fifth, the program .I NFS-writes the message to the file. Sixth, the program .BR link() s the file to .BR destdir/\fItime.pid.host . At that instant the data has been successfully written. In addition, .I safecat starts a 24-hour timer before creating .BR tempdir/\fItime.pid.host , and aborts the write if the timer expires. Upon error, timeout, or normal completion, .I safecat attempts to .B unlink() .BR tempdir/\fItime.pid.host . .SH "EXIT STATUS" An exit status of 0 (success) implies that all data has been safely committed to disk. A non-zero exit status should be considered to mean failure, though there is an outside chance that .I safecat wrote the data successfully, but didn't think so. Note again that if a file appears in the destination directory, then it is guaranteed to be complete. If .I safecat completes successfully, then it will print the name of the newly created file (without its path) to standard output. .SH "SUGGESTED APPLICATIONS" Exciting uses for .I safecat abound, obviously, but a word may be in order to suggest what they are. If you run Linux and use qmail instead of sendmail, you should consider converting your inbox to .I maildir for its superior reliability. If your home directory is NFS mounted, qmail forces you to use .IR maildir . On the downside, the lovely tool .IR procmail , which filters your spam, does not know .IR maildir . Rather than running the patched .IR procmail , you might consider using .I safecat to deliver to your inbox. That allows you to use the latest .I procmail without waiting for the .I maildir patches to be applied to it. (Note: the previous paragraph was written before .I procmail started handling maildir delivery. Since maildir delivery has been added, my point is made .IR stronger ! .IR Procmail 's maildir support does not comply with Dan's algorithm, and so does not offer the reliability promised by maildir delivery. .I Procmail plus .I safecat has always offered reliable maildir delivery. Another victory for modularity!) If you write CGI applications to collect data over the World Wide Web, you might find .I safecat useful. Web applications suffer from two major problems. Their performance suffers from every stoppage or bottleneck in the internet; they cannot afford to introduce performance problems of their own. Additionally, web applications should NEVER leave the server and database in an inconsistent state. This is likely, however, if CGI scripts directly frob some database--particularly if the database is overloaded or slow. What happens when users get bored and click "Stop" or "Back"? Maybe the database activity completes. Maybe the CGI script is killed, leaving the DB in an inconsistent state. Consider the following strategy. Make your CGI script dump its request to a spool directory using .IR safecat . Immediately return a receipt to the browser. Now the browser has a complete guarantee that their submission is received, and the perceived performance of your web application is optimal. Meanwhile, a spooler daemon notices the fresh request, snatches it and updates the database. Browsers can be informed that their request will be fulfilled in X minutes. The result is optimal performance despite a capricious internet. In addition, users can be offered nearly 100% reliability. .SH EXAMPLES To convince sendmail to use .I maildir for message delivery, add the following line to your .forward file: .na .nf .sp .B |SAFECAT HOME/Maildir/tmp HOME/Maildir/new || exit 75 #USERNAME .sp .fi where .B SAFECAT is the complete path of the .I safecat program, .B HOME is the complete path to your home directory, and .B USERNAME is your login name. Making this change is likely to pay off; many campuses and companies mount user home directories with NFS. Using .I maildir to deliver to your inbox folder helps ensure that your mail will not be lost due to some NFS error. Of course, if you are a System Administrator, you should consider switching to qmail. To run a program and catch its output safely into some directory, you can use a shell script like the following. .na .nf .sp #!/bin/bash MYPROGRAM=cat # The program you want to run TEMPDIR=/tmp # The name of a temporary directory DESTDIR=$HOME/work/data # The directory for storing information try() { $* 2>/dev/null || echo NO 1>&2 } set `( try $MYPROGRAM | try safecat $TEMPDIR $DESTDIR ) 2>&1` test "$?" = "0" || exit -1 test "$1" = "NO" && { rm -f $DESTDIR/$2; exit -1; } .sp .fi This script illustrates the pitfalls of writing secure programs with the shell. The script assumes that your program might generate some output, but then fail to complete. There is no way for .I safecat to know whether your program completed successfully or not, because of the semantics of the shell. As a result, safecat might create a file in the data directory which is "complete" but not useful. The shell script deletes the file in that case. More generally, the safest way to use .I safecat is from within a C program which invokes safecat with .I fork() and .IR execve() . The parent process can the simply .I kill() the .I safecat process if any problems develop, and optionally can try again. Whether to go to this trouble depends upon how serious you are about protecting your data. Either way, .I safecat will not be the weak link in your data flow. .SH BUGS In order to perform the last step and .I link() the temporary file into the destination directory, both directories must reside in the same file system. If they do not, .I safecat will quietly fail every time. In Professor Bernstein's implementation of .IR maildir , the temporary and destination directories are required to belong to the same parent directory, which essentially avoids this problem. We relax this requirement to provide some flexibility, at the cost of some risk. Caveat emptor. Although .I safecat cleans up after itself, it may sometimes fail to delete the temporary file located in .IR tempdir . Since safecat times out after 24 hours, you may freely delete any temporary files older than 36 hours. Files newer than 36 hours should be left alone. A system of data flow involving safecat should include a cron job to clean up temporary files, or should obligate consumers of the data to do the cleanup, or both. In the case of qmail, mail readers using .I maildir are expected to scan and clean up the temporary directory. The guarantee of safe delivery of data is only "as certain as UNIX will allow." In particular, a disk hardware failure could result in .I safecat concluding that the data was safe, when it was not. Similarly, a successful exit status from .I safecat is of no value if the computer, its disks and backups all explode at some subsequent time. In other words, if your data is vital to you, then you won't just use .IR safecat . You'll also invest in good equipment (possibly including a RAID disk), a UPS for the server and drives, a regular backup schedule, and competent system administration. For many purposes, however, .I safecat can be considered 100% reliable. Also note that .I safecat was designed for spooling email messages; it is not the right tool for spooling large files--files larger than 2GB, for example. Some operating systems have a bug which causes safecat to fail silently when spooling files larger than 2GB. When building .IR safecat , you can take advantage of conditional support for large files on Linux; see .I conf-cc for further information. .SH CREDITS The .I maildir algorithm was devised by Professor Daniel Bernstein, the author of qmail. Parts of this manpage borrow directly from maildir(5) by Professor Bernstein. In particular, the section "THE MAILDIR ALGORITHM" transplants his explanation of the .I maildir algorithm in order to illustrate that .I safecat complies with it. The original code for .I safecat was written by the present author, but was since augmented with heavy borrowings from qmail code. However, under no circumstances should the author of qmail be contacted concerning safecat bugs; all are the fault, and the responsibility, of the present author. Copyright (c) 2000, Len Budney. All rights reserved. .SH "SEE ALSO" mbox(5), qmail-local(8), maildir(5) safecat-1.13/safecat.c0000664000076400007640000000771710110255772014202 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ /* safecat.c -- write stdin to a directory using the maildir algorithm. * * Safecat implements the maildir algorithm of Professor DJ Bernstein, * which is also used by his mail agent Qmail. This program can be * used to deliver data to a qmail maildir from a shell script, * safely, or for other related purposes (such as spooling data to a * directory). */ #include "alloc.h" #include "sig.h" #include "stat_dir.h" #include "stralloc.h" #include "strerr.h" #include "subfd.h" #include "tempfile.h" #include "version.h" #include "writefile.h" #include #include #include #include #include #include /* Support for large files (on Linux systems, if the appropriate compile-time flag is used. */ #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif /* Function prototypes. */ static void die_nomem() { strerr_die2x(111,"safecat: fatal: ","out of memory"); } stralloc tmppath = {0}; /* ****************************************************************** */ int main(int argc, char *argv[]) { char *tempdir = NULL; char *destdir = NULL; int outfd = 0; stralloc dstpath = {0}; stralloc outfile = {0}; stralloc outpath = {0}; struct stat filestat; unsigned int count = 0; /* Check that we were called with the correct number of arguments. */ if(argc != 3) { strerr_die2x(100, "safecat: usage: ","safecat "); } /* Scan the command line arguments, to get the temp directory and destination directory names. */ tempdir = argv[1]; destdir = argv[2]; /* Declare a handler for SIGALRM so we can time out. */ set_handler(SIGALRM, alarm_handler); /* Step 1: Check that the supplied directories are OK. */ stat_dir(tempdir); stat_dir(destdir); /* Step 2: Stat the temporary file. Wait for ENOENT as a response. */ for(count=1;;count++) { /* Get the temporary filename to use now for dumping data. */ mk_tempfile(&outfile); if (!stralloc_cats(&outpath,tempdir)) die_nomem(); if (!stralloc_append(&outpath, "/")) die_nomem(); if (!stralloc_cat(&outpath,&outfile)) die_nomem(); if(stat(outpath.s,&filestat) == -1 && errno == ENOENT) { if (!stralloc_cats(&dstpath, destdir)) die_nomem(); if (!stralloc_append(&dstpath, "/")) die_nomem(); if (!stralloc_cat(&dstpath,&outfile)) die_nomem(); if (!stralloc_cats(&tmppath, tempdir)) die_nomem(); if (!stralloc_append(&tmppath, "/")) die_nomem(); if (!stralloc_cat(&tmppath,&outfile)) die_nomem(); break; } /* Try up to 5 times, every 2 seconds. */ if(count == 5) { strerr_die2x(111, "safecat: fatal: ","could not stat temporary file"); } /* Wait 2 seconds, and try again. */ stralloc_copys(&outfile,""); stralloc_copys(&outpath,""); sleep(2); } /* Step 4: Create the file tempdir/time.MusecPpid.host */ alarm(86400); outfd = open(tmppath.s,O_WRONLY | O_EXCL | O_CREAT | O_LARGEFILE,0644); if(outfd == -1) { strerr_die2sys(111,"safecat: fatal: ","couldn't create output file: "); } /* Step 5: Copy stdin to the temp file. */ writefile(outfd); /* Close the file, checking the return value. */ if(fsync(outfd) == -1 || close(outfd) == -1) { unlink(tmppath.s); strerr_die2sys(111,"safecat: fatal: ","can't fsync/close output file: "); } /* Step 6: Link the temp file to its final destination. */ if(link(tmppath.s,dstpath.s) == -1) { unlink(tmppath.s); strerr_die2sys(111,"safecat: fatal: ","can't link output file: "); } /* We've succeeded! Now, no matter what, we return "success" */ /* Okay, delete the temporary file. If it fails, bummer. */ unlink(tmppath.s); /* Print the name of the file we've created, as a curtesy. */ substdio_puts(subfdoutsmall,outfile.s); substdio_puts(subfdoutsmall,"\n"); substdio_flush(subfdoutsmall); exit(0); } /* ****************************************************************** */ safecat-1.13/safecat.spec0000664000076400007640000000347510416221704014704 0ustar budneybudneySummary: Secure spooling of emails to a qmail maildir Name: safecat Version: 1.13 Release: v1 License: BSD Group: Applications/File Source: http://www.pobox.com/~lbudney/linux/software/safecat/safecat-%{version}.tar.gz Patch0: safecat-buildroot.patch URL: http://www.pobox.com/~lbudney/linux/software/safecat.html Packager: Vadim Druzhin BuildRoot: /var/tmp/%{name}-%{version}-%{release} %description safecat implements Dan Bernstein's maildir algorithm, copying standard input safely to a specified directory. With safecat, the user is offered two assurances. First, if safecat returns successfully, then all data is guaranteed to be saved in the destination directory. Second, if a file exists in the destination directory, placed there by safecat, then the file is guaranteed to be complete. To use safecat, you specify a destination directory, but not a file name. Safecat picks the filename uniquely every time. That way many safecat processes (and other programs) can write to the directory simultaneously. If you want a particular filename, then you just rename the file after safecat completes. In general you should use a single, separate process to do things like renaming, collecting, and deleting files. You can run the process as a daemon, a cron jobs, or from a mail reader. %prep %setup # BUILD_ROOT patch %patch0 echo "/usr" > conf-root %build make %install if [ x"$RPM_BUILD_ROOT" != x"/" -a -d "$RPM_BUILD_ROOT" ] then rm -rf "$RPM_BUILD_ROOT" fi mkdir -p "$RPM_BUILD_ROOT" make setup check %clean if [ x"$RPM_BUILD_ROOT" != x"/" -a -d "$RPM_BUILD_ROOT" ] then rm -rf "$RPM_BUILD_ROOT" fi %files %defattr(-,root,root) %doc CHANGES README INSTALL COPYING /usr/bin/safecat /usr/bin/maildir /usr/man/man1/safecat.1.gz /usr/man/man1/maildir.1.gz /usr/man/cat1/safecat.0 /usr/man/cat1/maildir.0 safecat-1.13/sig.c0000664000076400007640000000175507056643244013364 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ #include "hassgact.h" #include "stralloc.h" #include "strerr.h" #include #include /* ****************************************************************** */ extern stralloc tmppath; void alarm_handler(int sig) { unlink(tmppath.s); strerr_die2x(111,"safecat: fatal: ","Timer has expired; giving up"); } /* ****************************************************************** */ /* ****************************************************************** This function was pretty much lifted from Qmail code. Thanks to Professor Bernstein. ****************************************************************** */ void set_handler(int sig, void (*h)()) { #ifdef HASSIGACTION struct sigaction sa; sa.sa_handler = h; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(sig,&sa,(struct sigaction *) 0); #else signal(sig,h); #endif } /* ****************************************************************** */ safecat-1.13/sig.h0000664000076400007640000000030107056643244013353 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ /* Signal handler for SIGALRM and signal handler setter. */ void set_handler(int sig, void (*f)()); void alarm_handler(int sig); safecat-1.13/stat_dir.c0000664000076400007640000000131110110253547014363 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ #include "stat_dir.h" #include "strerr.h" #include #include /* ****************************************************************** */ void stat_dir(char *dirname) { struct stat filestat; if(stat(dirname,&filestat) != 0) { strerr_die2sys(111,"safecat: fatal: ","could not stat directory: "); } if( !S_ISDIR(filestat.st_mode) ) { strerr_die2x(111, "safecat: fatal: ","not a directory"); } if((filestat.st_mode & S_IWUSR) != S_IWUSR) { strerr_die2x(111, "safecat: fatal: ","directory not writable"); } filestat.st_mode = 0; } /* ****************************************************************** */ safecat-1.13/stat_dir.h0000664000076400007640000000014707020761630014401 0ustar budneybudney/* Check whether a directory exists, is a directory, and is writable. */ void stat_dir(char *dirname); safecat-1.13/str.h0000664000076400007640000000056207056643244013412 0ustar budneybudney#ifndef STR_H #define STR_H extern unsigned int str_copy(char *,char *); extern int str_diff(char *,char *); extern int str_diffn(char *,char *,unsigned int); extern unsigned int str_len(char *); extern unsigned int str_chr(char *,int); extern unsigned int str_rchr(char *,int); extern int str_start(char *,char *); #define str_equal(s,t) (!str_diff((s),(t))) #endif safecat-1.13/str_diffn.c0000664000076400007640000000104607056643244014551 0ustar budneybudney#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); } safecat-1.13/str_len.c0000664000076400007640000000034307056643244014240 0ustar budneybudney#include "str.h" unsigned int str_len(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; } } safecat-1.13/stralloc.30000664000076400007640000000510007056643244014331 0ustar budneybudney.TH stralloc 3 .SH NAME stralloc \- dynamically allocated strings .SH SYNTAX .B #include int \fBstralloc_ready\fP(&\fIsa\fR,\fIlen\fR); .br int \fBstralloc_readyplus\fP(&\fIsa\fR,\fIlen\fR); int \fBstralloc_copy\fP(&\fIsa\fR,&\fIsa2\fR); .br int \fBstralloc_copys\fP(&\fIsa\fR,\fIbuf\fR); .br int \fBstralloc_copyb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); int \fBstralloc_cat\fP(&\fIsa\fR,&\fIsa2\fR); .br int \fBstralloc_cats\fP(&\fIsa\fR,\fIbuf\fR); .br int \fBstralloc_catb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); int \fBstralloc_append\fP(&\fIsa\fR,\fIbuf\fR); .br int \fBstralloc_0\fP(&\fIsa\fR); int \fBstralloc_starts\fP(&\fIsa\fR,\fIbuf\fR); stralloc \fIsa\fR = {0}; .br stralloc \fIsa2\fR = {0}; .br unsigned int \fIlen\fR; .br char *\fIbuf\fR; .SH DESCRIPTION A .B stralloc variable holds a string in dynamically allocated space. String length is limited only by memory. String contents are unrestricted. The .B stralloc structure has three components: .I sa\fB.s is a pointer to the string, or 0 if it is not allocated; .I sa\fB.len is the number of bytes in the string, if it is allocated; .I sa\fB.a is the number of bytes allocated for the string, if it is allocated. A .B stralloc variable should be initialized to {0}, meaning unallocated. .B stralloc_ready makes sure that .I sa has enough space allocated for .I len characters. It allocates extra space if necessary. .B stralloc_readyplus makes sure that .I sa has enough space allocated for .I len characters more than its current length. If .I sa is unallocated, .B stralloc_readyplus is the same as .BR stralloc_ready . .B stralloc_copy copies .I sa2 to .IR sa , allocating space if necessary. Here .I sa2 is an allocated .B stralloc variable. .B stralloc_copys copies a 0-terminated string, .IR buf , to .IR sa , without the 0. .B stralloc_copyb copies .I len characters from .I buf to .IR sa . .B stralloc_cat appends .I sa2 to .IR sa , allocating space if necessary. If .I sa is unallocated, .B stralloc_cat is the same as .BR stralloc_copy . .B stralloc_cats and .B stralloc_catb are analogous to .B stralloc_copys and .BR stralloc_copyb . .B stralloc_append adds a single character, .IR *buf , to .IR sa , allocating space if necessary. .B stralloc_0 adds a single 0 character to .IR sa . .B stralloc_starts returns 1 if the 0-terminated string .IR buf , without the 0, is a prefix of .IR sa . .SH "ERROR HANDLING" If a .B stralloc routine runs out of memory, it leaves .I sa alone and returns 0, setting .B errno appropriately. On success it returns 1; this guarantees that .I sa is allocated. .SH "SEE ALSO" alloc(3), error(3) safecat-1.13/stralloc.h0000664000076400007640000000152607056643244014426 0ustar budneybudney#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,"") extern int stralloc_catulong0(); extern int stralloc_catlong0(); #define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0)) #define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(unsigned long) (i),(n))) #define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(long) (i),(n))) #define stralloc_catint(sa,i) (stralloc_catlong0((sa),(long) (i),0)) #endif safecat-1.13/stralloc_arts.c0000664000076400007640000000030407056643244015443 0ustar budneybudney#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); } safecat-1.13/stralloc_cat.c0000664000076400007640000000024107056643244015241 0ustar budneybudney#include "byte.h" #include "stralloc.h" int stralloc_cat(sato,safrom) stralloc *sato; stralloc *safrom; { return stralloc_catb(sato,safrom->s,safrom->len); } safecat-1.13/stralloc_catb.c0000664000076400007640000000050007056643244015401 0ustar budneybudney#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; } safecat-1.13/stralloc_cats.c0000664000076400007640000000022607056643244015427 0ustar budneybudney#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)); } safecat-1.13/stralloc_copy.c0000664000076400007640000000024307056643244015446 0ustar budneybudney#include "byte.h" #include "stralloc.h" int stralloc_copy(sato,safrom) stralloc *sato; stralloc *safrom; { return stralloc_copyb(sato,safrom->s,safrom->len); } safecat-1.13/stralloc_eady.c0000664000076400007640000000031307056643244015414 0ustar budneybudney#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) safecat-1.13/stralloc_num.c0000664000076400007640000000107707056643244015301 0ustar budneybudney#include "stralloc.h" int stralloc_catulong0(sa,u,n) stralloc *sa; unsigned long u; unsigned int n; { unsigned int len; unsigned long q; char *s; len = 1; q = u; while (q > 9) { ++len; q /= 10; } if (len < n) len = n; if (!stralloc_readyplus(sa,len)) return 0; s = sa->s + sa->len; sa->len += len; while (len) { s[--len] = '0' + (u % 10); u /= 10; } return 1; } int stralloc_catlong0(sa,l,n) stralloc *sa; long l; unsigned int n; { if (l < 0) { if (!stralloc_append(sa,"-")) return 0; l = -l; } return stralloc_catulong0(sa,l,n); } safecat-1.13/stralloc_opyb.c0000664000076400007640000000037707056643244015455 0ustar budneybudney#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; } safecat-1.13/stralloc_opys.c0000664000076400007640000000023007056643244015462 0ustar budneybudney#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)); } safecat-1.13/stralloc_pend.c0000664000076400007640000000023107056643244015417 0ustar budneybudney#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) safecat-1.13/strcat_alloc.c0000664000076400007640000000146607020761630015242 0ustar budneybudney#include "config.h" #include "strcat_alloc.h" #include #include #include /* ****************************************************************** */ char *strcat_alloc(const char *path,const char *filename) { /* Allocate a pointer to return. */ char *retval = (char *)malloc(strlen(path) + strlen(filename) + 2); if(retval == NULL) { fprintf(stderr, "Could not allocate memory.\n"); exit(1); } /* Copy the path and filename to the destination string. */ memcpy(retval,path,strlen(path)); if(retval[strlen(path)] != '/') { retval[strlen(path)] = '/'; retval[strlen(path) + 1] = '\0'; } /* Append the temp filename to our new strings. */ strcat(retval,filename); return(retval); } /* ****************************************************************** */ safecat-1.13/strcat_alloc.h0000664000076400007640000000017707020761630015245 0ustar budneybudney/* Catenate two strings, storing the result in allocated memory. */ char *strcat_alloc(const char *path,const char *filename); safecat-1.13/strerr.h0000664000076400007640000000644307056643244014127 0ustar budneybudney#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 safecat-1.13/strerr_die.c0000664000076400007640000000154607056643244014742 0ustar budneybudney#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); } safecat-1.13/strerr_sys.c0000664000076400007640000000030007056643244015002 0ustar budneybudney#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 = ""; } safecat-1.13/subfd.h0000664000076400007640000000040707056643244013703 0ustar budneybudney#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 safecat-1.13/subfderr.c0000664000076400007640000000026207056643244014406 0ustar budneybudney#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 = ⁢ safecat-1.13/subfdin.c0000664000076400007640000000052407056643244014225 0ustar budneybudney#include "readwrite.h" #include "substdio.h" #include "subfd.h" int subfd_read(fd,buf,len) int fd; char *buf; int len; { if (substdio_flush(subfdout) == -1) return -1; return read(fd,buf,len); } char subfd_inbuf[SUBSTDIO_INSIZE]; static substdio it = SUBSTDIO_FDBUF(subfd_read,0,subfd_inbuf,SUBSTDIO_INSIZE); substdio *subfdin = ⁢ safecat-1.13/subfdins.c0000664000076400007640000000053207056643244014407 0ustar budneybudney#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 = ⁢ safecat-1.13/subfdout.c0000664000076400007640000000031407056643244014423 0ustar budneybudney#include "readwrite.h" #include "substdio.h" #include "subfd.h" char subfd_outbuf[SUBSTDIO_OUTSIZE]; static substdio it = SUBSTDIO_FDBUF(write,1,subfd_outbuf,SUBSTDIO_OUTSIZE); substdio *subfdout = ⁢ safecat-1.13/subfdouts.c0000664000076400007640000000030107056643244014602 0ustar budneybudney#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 = ⁢ safecat-1.13/substdi.c0000664000076400007640000000311707056643244014251 0ustar budneybudney#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; } safecat-1.13/substdio.c0000664000076400007640000000034707056643244014432 0ustar budneybudney#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; } safecat-1.13/substdio.h0000664000076400007640000000171407056643244014436 0ustar budneybudney#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 safecat-1.13/substdio_copy.c0000664000076400007640000000053307056643244015461 0ustar budneybudney#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); } } safecat-1.13/substdo.c0000664000076400007640000000374507056643244014266 0ustar budneybudney#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)); } safecat-1.13/tai.h0000664000076400007640000000046707056643244013363 0ustar budneybudney#ifndef TAI_H #define TAI_H #include "uint64.h" struct tai { uint64 x; } ; extern void tai_now(); #define tai_approx(t) ((double) ((t)->x)) extern void tai_add(); extern void tai_sub(); #define tai_less(t,u) ((t)->x < (u)->x) #define TAI_PACK 8 extern void tai_pack(); extern void tai_unpack(); #endif safecat-1.13/taia.h0000664000076400007640000000100507056643244013511 0ustar budneybudney#ifndef TAIA_H #define TAIA_H #include "tai.h" struct taia { struct tai sec; unsigned long nano; /* 0...999999999 */ unsigned long atto; /* 0...999999999 */ } ; extern void taia_tai(); extern void taia_now(); extern double taia_approx(); extern double taia_frac(); extern void taia_add(); extern void taia_sub(); extern void taia_half(); extern int taia_less(); #define TAIA_PACK 16 extern void taia_pack(); extern void taia_unpack(); #define TAIA_FMTFRAC 19 extern unsigned int taia_fmtfrac(); #endif safecat-1.13/taia_fmtfrac.c0000664000076400007640000000144007056643244015211 0ustar budneybudney#include "taia.h" unsigned int taia_fmtfrac(s,t) char *s; struct taia *t; { unsigned long x; if (s) { x = t->atto; s[17] = '0' + (x % 10); x /= 10; s[16] = '0' + (x % 10); x /= 10; s[15] = '0' + (x % 10); x /= 10; s[14] = '0' + (x % 10); x /= 10; s[13] = '0' + (x % 10); x /= 10; s[12] = '0' + (x % 10); x /= 10; s[11] = '0' + (x % 10); x /= 10; s[10] = '0' + (x % 10); x /= 10; s[9] = '0' + (x % 10); x = t->nano; s[8] = '0' + (x % 10); x /= 10; s[7] = '0' + (x % 10); x /= 10; s[6] = '0' + (x % 10); x /= 10; s[5] = '0' + (x % 10); x /= 10; s[4] = '0' + (x % 10); x /= 10; s[3] = '0' + (x % 10); x /= 10; s[2] = '0' + (x % 10); x /= 10; s[1] = '0' + (x % 10); x /= 10; s[0] = '0' + (x % 10); } return 18; } safecat-1.13/taia_now.c0000664000076400007640000000047407056643244014400 0ustar budneybudney#include #include #include "taia.h" /* XXX: breaks tai encapsulation */ void taia_now(t) struct taia *t; { struct timeval now; gettimeofday(&now,(struct timezone *) 0); t->sec.x = 4611686018427387914ULL + (uint64) now.tv_sec; t->nano = 1000 * now.tv_usec + 500; t->atto = 0; } safecat-1.13/taia_tai.c0000664000076400007640000000013307056643244014342 0ustar budneybudney#include "taia.h" void taia_tai(ta,t) struct taia *ta; struct tai *t; { *t = ta->sec; } safecat-1.13/tempfile.c0000664000076400007640000000300607700312225014362 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ #include "hostname.h" #include "stralloc.h" #include "strerr.h" #include "tai.h" #include "taia.h" #include "fmt.h" #include static void die_nomem() { strerr_die2x(111,"safecat: fatal: ","out of memory"); } /* ****************************************************************** */ void mk_tempfile(stralloc *tmpf) { char host[256]; char secbuf[11]; char atto[TAIA_FMTFRAC]; char pidbuf[6]; struct taia now; struct tai sec; unsigned long int pid = (unsigned long)getpid(); /* Get a microsecond timestamp with which to build a filename. */ taia_now(&now); taia_tai(&now,&sec); /* Record the second timestamp on the string. */ secbuf[fmt_uint64(secbuf,(uint64) sec.x - 4611686018427387904)] = '\0'; if (!stralloc_cats(tmpf, secbuf)) die_nomem(); /* Append the microsecond timestamp to the string. */ if (!stralloc_cats(tmpf, ".M")) die_nomem(); taia_fmtfrac(atto,&now); atto[6] = '\0'; /* truncate at microsecond */ if (!stralloc_cats(tmpf, atto)) die_nomem(); /* Append the PID to the string. */ if (!stralloc_append(tmpf, "P")) die_nomem(); pidbuf[fmt_uint64(pidbuf, pid)] = '\0'; if (!stralloc_cats(tmpf, pidbuf)) die_nomem(); /* Copy the hostname to the buffer. */ if (!stralloc_append(tmpf, ".")) die_nomem(); get_hostname(host,sizeof(host)); if (!stralloc_cats(tmpf, host)) die_nomem(); if (!stralloc_0(tmpf)) die_nomem(); } /* ****************************************************************** */ safecat-1.13/tempfile.h0000664000076400007640000000030107056643244014376 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ /* Create a temporary file, using a timestamp, PID, and the hostname. */ #include "stralloc.h" void mk_tempfile(stralloc *tmpf); safecat-1.13/trycpp.c0000664000076400007640000000014407056643244014112 0ustar budneybudneyvoid main() { #ifdef NeXT printf("nextstep\n"); exit(0); #endif printf("unknown\n"); exit(0); } safecat-1.13/tryerrno.c0000644000076400007640000000010110016011436014422 0ustar budneybudney#include void main() { errno = 0; _exit(errno); } safecat-1.13/trysgact.c0000664000076400007640000000025307056643244014432 0ustar budneybudney#include void main() { struct sigaction sa; sa.sa_handler = 0; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(0,&sa,(struct sigaction *) 0); } safecat-1.13/tryulong32.c0000664000076400007640000000051407056643244014622 0ustar budneybudneyvoid 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); } safecat-1.13/tryulong64.c0000664000076400007640000000052307474314471014630 0ustar budneybudneyint 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(1); _exit(0); } safecat-1.13/uint32.h10000664000076400007640000000011007056643244013774 0ustar budneybudney#ifndef UINT32_H #define UINT32_H typedef unsigned int uint32; #endif safecat-1.13/uint32.h20000664000076400007640000000011107056643244013776 0ustar budneybudney#ifndef UINT32_H #define UINT32_H typedef unsigned long uint32; #endif safecat-1.13/uint64.h10000664000076400007640000000014607474314471014013 0ustar budneybudney#ifndef UINT64_H #define UINT64_H /* sysdep: -ulong64 */ typedef unsigned long long uint64; #endif safecat-1.13/uint64.h20000664000076400007640000000014107474314471014007 0ustar budneybudney#ifndef UINT64_H #define UINT64_H /* sysdep: +ulong64 */ typedef unsigned long uint64; #endif safecat-1.13/warn-auto.sh0000664000076400007640000000010007056643244014666 0ustar budneybudney#!/bin/sh # WARNING: This file was auto-generated. Do not edit! safecat-1.13/writefile.c0000664000076400007640000000235307242121565014561 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ #include "env.h" #include "stralloc.h" #include "strerr.h" #include "subfd.h" #include "substdio.h" #include "writefile.h" #include #include extern stralloc tmppath; /* ****************************************************************** */ void writefile(int fd) { char inbuf[512]; char outbuf[512]; char *dtline; char *rpline; substdio ssin; substdio ssout; /* Prepare substdio buffers for reading and writing. */ substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf)); substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); /* Print DTLINE and RPLINE, if supplied. */ dtline = env_get("DTLINE"); rpline = env_get("RPLINE"); if (dtline && rpline) { if(substdio_puts(&ssout,rpline) == -1) goto fail; if(substdio_puts(&ssout,dtline) == -1) goto fail; } /* Copy stdin to the output file, watching the return values each time. */ if (substdio_copy(&ssout,&ssin) < 0) goto fail; if (substdio_flush(&ssout) == -1) goto fail; /* The file is copied. */ return; fail: unlink(tmppath.s); strerr_die2x(111,"safecat: fatal: ","unable to copy standard input"); } /* ****************************************************************** */ safecat-1.13/writefile.h0000664000076400007640000000024707056643244014574 0ustar budneybudney/* Copyright (c) 2000, Len Budney. See COPYING for details. */ /* Copy stdin to the given file descriptor, treating all failures as fatal. */ void writefile(int fd); safecat-1.13/error.h0000664000076400007640000000072410110252557013717 0ustar budneybudney#ifndef ERROR_H #define ERROR_H #include "error_no.h" 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 int error_nodevice; extern char *error_str(int); extern int error_temp(int); #endif safecat-1.13/error_no.h20000644000076400007640000000002207740615761014501 0ustar budneybudneyextern int errno; safecat-1.13/error_no.h10000644000076400007640000000002307740615761014501 0ustar budneybudney#include