/*
* newsspool - copy incoming news into incoming directory
* -Log-
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include "fixerrno.h"
#include "libc.h"
#include "news.h"
#include "config.h"
#ifndef lint
static char RCSid[] = "$Header$";
#endif
#ifndef MAXTRIES
#define MAXTRIES 100 /* limit on attempts to make links */
#endif
int debug = 0;
char *progname;
extern void error();
#ifdef UTZOOERR
extern char *mkprogname();
#else
#define mkprogname(a) (a)
#endif
char buf[BUFSIZ*16]; /* try to get a batch in a few gulps */
char *suffix = ".t"; /* suffix for filename, default is plain text */
char grade[3] = ""; /* 3 = digit, period, NUL */
void process();
FILE *outopen();
void outclose();
extern time_t time();
char *outname();
/*
- main - parse arguments and handle options
*/
main(argc, argv)
int argc;
char *argv[];
{
int c;
int errflg = 0;
FILE *in;
struct stat statbuf;
extern int optind;
extern char *optarg;
extern FILE *efopen();
void process();
progname = mkprogname(argv[0]);
while ((c = getopt(argc, argv, "g:d")) != EOF)
switch (c) {
case 'g': /* grade */
if (strchr("0123456789", *optarg) == NULL)
error("invalid grade `%s'", optarg);
sprintf(grade, "%c.", *optarg);
break;
case 'd': /* Debugging. */
debug++;
setbuf(stderr, (char *)NULL);
break;
case '?':
default:
errflg++;
break;
}
if (errflg) {
fprintf(stderr, "usage: %s [file] ...\n", progname);
exit(2);
}
/* probe to get unprivileged() called if necessary */
(void) ctlfile((char *)NULL);
/* mktemp() uses access(2) [ARGH!] so minimize chances of trouble */
(void) setgid(getegid());
(void) setuid(geteuid());
(void) umask(newsumask());
if (optind >= argc)
process(stdin, "stdin");
else
for (; optind < argc; optind++)
if (STREQ(argv[optind], "-"))
process(stdin, "-");
else {
in = efopen(argv[optind], "r");
if (fstat(fileno(in), &statbuf) < 0)
error("can't fstat `%s'", argv[optind]);
process(in, argv[optind]);
(void) fclose(in);
}
exit(0);
}
/*
* process - process input file
*/
/* ARGSUSED */
void
process(in, inname)
FILE *in;
char *inname;
{
register int count;
register int firstblock;
FILE *out;
register char *p;
register int n;
char *name;
register int wrotesome = 0;
name = outname();
out = outopen(name);
/* do the copying */
firstblock = 1;
while ((count = fread(buf, sizeof(char), sizeof(buf), in)) > 0) {
if (firstblock) {
n = cunskip(buf, count);
p = buf + n;
count -= n;
firstblock = 0;
} else
p = buf;
if (count > 0) {
n = fwrite(p, sizeof(char), count, out);
if (n != count)
error("write error in output to `%s'", name);
wrotesome = 1;
}
}
outclose(out, name, wrotesome);
}
/*
- outname - construct name for the temporary output file
*/
char *
outname()
{
register char *p;
p = strsave(fullartfile("in.coming/nspool.XXXXXX"));
mktemp(p);
return(p);
}
/*
- outopen - acquire an output file
*/
FILE *
outopen(name)
char *name;
{
FILE *f;
f = fopen(name, "w");
if (f == NULL)
error("unable to create temporary `%s'", name);
if (debug)
fprintf(stderr, "output into %s\n", name);
return(f);
}
/*
- outclose - close output file, moving it to the right place
*
* Names are based on the current time in hopes of keeping input in order.
*/
void
outclose(f, tmpname, wrotesome)
FILE *f;
char *tmpname;
int wrotesome; /* did anything actually get written to it? */
{
register char *p;
register char *name;
register int ntries;
time_t now;
if (nfclose(f) == EOF)
error("close error on file `%s'", tmpname);
if (!wrotesome) {
(void) unlink(tmpname);
return;
}
if (!mkinperm(tmpname, grade, suffix))
error("couldn't move %s into the in.coming queue", tmpname);
if (debug)
fprintf(stderr, "succeeded\n");
}
/*
- cunskip - inspect block for silly #! cunbatch headers, classify input
*/
int /* number of chars at start to skip */
cunskip(bufp, count)
char *bufp;
int count;
{
static char goop[] = "cunbatch";
# define GOOPLEN (sizeof(goop)-1) /* strlen(goop) */
static char suf[] = ".Z";
static char comp[] = "\037\235"; /* compress's magic no. */
register char *p;
register int nleft;
# define MINCBATCH 5 /* one character, compressed */
nleft = count;
p = bufp;
if (nleft < 2) /* no room for a header */
return(0);
if (p[0] == comp[0] && p[1] == comp[1]) { /* compressed */
if (nleft < MINCBATCH)
return(count);
suffix = suf;
return(0);
}
if (*p++ != '#' || *p++ != '!') /* doesn't start with #! */
return(0);
nleft -= 2;
/* skip space */
while (nleft > 0 && (*p == ' ' || *p == '\t')) {
p++;
nleft--;
}
/* recognize headers (the +1s ensure room for the newline) */
if (nleft >= GOOPLEN+1 && STREQN(p, goop, GOOPLEN)) {
p += GOOPLEN;
nleft -= GOOPLEN;
suffix = suf;
} else /* no header */
return(0);
/* skip more space */
while (nleft > 0 && (*p == ' ' || *p == '\t')) {
p++;
nleft--;
}
if (nleft == 0 || *p++ != '\n') /* didn't end properly */
return(0);
if (nleft < MINCBATCH) /* null batch */
return(count);
return(p - bufp);
}
/*
- unprivileged - drop setuidness if configuration is overridden
*/
/* ARGSUSED */
void
unprivileged(reason)
char *reason;
{
setgid(getgid());
setuid(getuid());
/* tempting to complain, but it fouls up the regression test */
}
syntax highlighted by Code2HTML, v. 0.9.1