⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 batcher.c

📁 早期freebsd实现
💻 C
字号:
/*  $Revision: 1.17 $****  Read batchfiles on standard input and spew out batches.*/#include "configdata.h"#include <stdio.h>#include <fcntl.h>#include <ctype.h>#include <errno.h>#include <signal.h>#include <sys/types.h>#include <sys/stat.h>#if	defined(DO_NEED_TIME)#include <time.h>#endif	/* defined(DO_NEED_TIME) */#include <sys/time.h>#include "paths.h"#include "libinn.h"#include "logging.h"#include "clibrary.h"#include "macros.h"/***  Global variables.*/STATIC BOOL	BATCHopen;STATIC BOOL	STATprint;STATIC double	STATbegin;STATIC double	STATend;STATIC char	*Host;STATIC char	*InitialString;STATIC char	*Input;STATIC char	*Processor;STATIC int	ArtsInBatch;STATIC int	ArtsWritten;STATIC int	BATCHcount;STATIC int	MaxBatches;STATIC int	BATCHstatus;STATIC long	BytesInBatch = 60 * 1024;STATIC long	BytesWritten;STATIC long	MaxArts;STATIC long	MaxBytes;STATIC SIGVAR	GotInterrupt;STATIC STRING	Separator = "#! rnews %ld";/***  Start a batch process.*/STATIC FILE *BATCHstart(){    FILE	*F;    char	buff[SMBUF];    if (Processor && *Processor) {	(void)sprintf(buff, Processor, Host);	F = popen(buff, "w");	if (F == NULL)	    return NULL;    }    else	F = stdout;    BATCHopen = TRUE;    BATCHcount++;    return F;}/***  Close a batch, return exit status.*/STATIC intBATCHclose(F)    FILE	*F;{    BATCHopen = FALSE;    if (F == stdout)	return fflush(stdout) == EOF ? 1 : 0;    return pclose(F);}/***  Update the batch file and exit.*/STATIC NORETURNRequeueAndExit(Cookie, line, BytesInArt)    OFFSET_T	Cookie;    char	*line;    long	BytesInArt;{    static char	LINE1[] = "batcher %s times user %.3f system %.3f elapsed %.3f";    static char	LINE2[] ="batcher %s stats batches %d articles %d bytes %ld";    static char	NOWRITE[] = "batcher %s cant write spool %s\n";    static char	BATCHDIR[] = _PATH_BATCHDIR;    char	temp[BUFSIZ];    char	buff[BUFSIZ];    int		i;    FILE	*F;    TIMEINFO	Now;    double	usertime;    double	systime;    /* Do statistics. */    (void)GetTimeInfo(&Now);    STATend = TIMEINFOasDOUBLE(Now);    if (GetResourceUsage(&usertime, &systime) < 0) {	usertime = 0;	systime = 0;    }    if (STATprint) {	(void)printf(LINE1, Host, usertime, systime, STATend - STATbegin);	(void)printf("\n");	(void)printf(LINE2, Host, BATCHcount, ArtsWritten, BytesWritten);	(void)printf("\n");    }    (void)openlog("batcher", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);    syslog(L_NOTICE, LINE1, Host, usertime, systime, STATend - STATbegin);    syslog(L_NOTICE, LINE2, Host, BATCHcount, ArtsWritten, BytesWritten);    /* Last batch exit okay? */    if (BATCHstatus == 0) {	if (feof(stdin)) {	    /* Yes, and we're all done -- remove input and exit. */	    (void)fclose(stdin);	    if (Input)		(void)unlink(Input);	    exit(0);	}	/* Don't seek back -- batch was fine. */	Cookie = -1;    }    /* Make an appropriate spool file. */    if (Input == NULL)	(void)sprintf(temp, "%s/%s", BATCHDIR, Host);    else	(void)sprintf(temp, "%s.bch", Input);    if ((F = xfopena(temp)) == NULL) {	(void)fprintf(stderr, "batcher %s cant open %s %s\n",	    Host, temp, strerror(errno));	exit(1);    }    /* If we can back up to where the batch started, do so. */    i = 0;    if (Cookie != -1 && fseek(stdin, Cookie, SEEK_SET) == -1) {	(void)fprintf(stderr, "batcher %s cant seek %s\n",		Host, strerror(errno));	i = 1;    }    /* Write the line we had; if the fseek worked, this will be an     * extra line, but that's okay. */    if (line && fprintf(F, "%s %ld\n", line, BytesInArt) == EOF) {	(void)fprintf(stderr, NOWRITE, Host, strerror(errno));	i = 1;    }    /* Write rest of stdin to spool. */    while (fgets(buff, sizeof buff, stdin) != NULL) 	if (fputs(buff, F) == EOF) {	    (void)fprintf(stderr, NOWRITE, Host, strerror(errno));	    i = 1;	    break;	}    if (fclose(F) == EOF) {	(void)fprintf(stderr, "batcher %s cant close spool %s\n",	    Host, strerror(errno));	i = 1;    }    /* If we had a named input file, try to rename the spool. */    if (Input != NULL && rename(temp, Input) < 0) {	(void)fprintf(stderr, "batcher %s cant rename spool %s\n",	    Host, strerror(errno));	i = 1;    }    exit(i);    /* NOTREACHED */}/***  Mark that we got interrupted.*/STATIC SIGHANDLERCATCHinterrupt(s)    int		s;{    GotInterrupt = TRUE;    /* Let two interrupts kill us. */    (void)signal(s, SIG_DFL);}/***  Print a usage message and exit.*/STATIC NORETURNUsage(){    (void)fprintf(stderr, "batcher usage_error.\n");    exit(1);}intmain(ac, av)    int		ac;    char	*av[];{    static char	SKIPPING[] = "batcher %s skipping \"%.40s...\" %s\n";    static char SPOOL[] = _PATH_SPOOL;    static char	BATCHDIR[] = _PATH_BATCHDIR;    BOOL	Redirect;    FILE	*F;    STRING	AltSpool;    TIMEINFO	Now;    char	*p;    char	*data;    char	line[BUFSIZ];    char	buff[BUFSIZ];    long	BytesInArt;    long	BytesInCB;    OFFSET_T	Cookie;    SIZE_T	datasize;    int		i;    int		artfd;    int		ArtsInCB;    int		length;    struct stat	Sb;    /* Set defaults. */    AltSpool = NULL;    Redirect = TRUE;    (void)umask(NEWSUMASK);    /* Parse JCL. */    while ((i = getopt(ac, av, "a:A:b:B:i:N:p:rs:S:v")) != EOF)	switch (i) {	default:	    Usage();	    /* NOTREACHED */	case 'a':	    ArtsInBatch = atoi(optarg);	    break;	case 'A':	    MaxArts = atol(optarg);	    break;	case 'b':	    BytesInBatch = atol(optarg);	    break;	case 'B':	    MaxBytes = atol(optarg);	    break;	case 'i':	    InitialString = optarg;	    break;	case 'N':	    MaxBatches = atoi(optarg);	    break;	case 'p':	    Processor = optarg;	    break;	case 'r':	    Redirect = FALSE;	    break;	case 's':	    Separator = optarg;	    break;	case 'S':	    AltSpool = optarg;	    break;	case 'v':	    STATprint = TRUE;	    break;	}    if (MaxArts && ArtsInBatch == 0)	ArtsInBatch = MaxArts;    if (MaxBytes && BytesInBatch == 0)	BytesInBatch = MaxBytes;    /* Parse arguments. */    ac -= optind;    av += optind;    if (ac != 1 && ac != 2)	Usage();    Host = av[0];    if ((Input = av[1]) != NULL) {	if (Input[0] != '/') {	    Input = NEW(char, STRLEN(BATCHDIR) + 1 + strlen(av[1]) + 1);	    (void)sprintf(Input, "%s/%s", BATCHDIR, av[1]);	}	if (freopen(Input, "r", stdin) == NULL) {	    (void)fprintf(stderr, "batcher %s cant open %s %s\n",		    Host, Input, strerror(errno));		exit(1);	}    }    if (Redirect)	(void)freopen(_PATH_ERRLOG, "a", stderr);    /* Go to where the articles are. */    if (chdir(SPOOL) < 0) {	(void)fprintf(stderr, "batcher %s cant cd %s %s\n",		Host, SPOOL, strerror(errno));	exit(1);    }    /* Set initial counters, etc. */    datasize = 8 * 1024;    data = NEW(char, datasize);    BytesInCB = 0;    ArtsInCB = 0;    Cookie = -1;    GotInterrupt = FALSE;    (void)signal(SIGHUP, CATCHinterrupt);    (void)signal(SIGINT, CATCHinterrupt);    (void)signal(SIGTERM, CATCHinterrupt);    /* (void)signal(SIGPIPE, CATCHinterrupt); */    (void)GetTimeInfo(&Now);    STATbegin = TIMEINFOasDOUBLE(Now);    F = NULL;    while (fgets(line, sizeof line, stdin) != NULL) {	/* Record line length in case we do an ftell. Not portable to	 * systems with non-Unix file formats. */	length = strlen(line);	/* Get lines like "name size" */	if ((p = strchr(line, '\n')) == NULL) {	    (void)fprintf(stderr, SKIPPING, Host, line, "too long");	    continue;	}	*p = '\0';	if (line[0] == '\0' || line[0] == COMMENT_CHAR)	    continue;	if ((p = strchr(line, ' ')) != NULL) {	    *p++ = '\0';	    BytesInArt = atol(p);	}	else	    BytesInArt = -1;	/* Strip of leading spool pathname. */	if (line[0] == '/'	 && line[STRLEN(SPOOL)] == '/'	 && EQn(line, SPOOL, STRLEN(SPOOL)))	    p = line + STRLEN(SPOOL) + 1;	else	    p = line;	/* Open the file. */	if ((artfd = open(p, O_RDONLY)) < 0) {	    if (errno != ENOENT)		(void)fprintf(stderr, SKIPPING, Host, p, strerror(errno));	    if (AltSpool == NULL)		continue;	    (void)sprintf(buff, "%s/%s", AltSpool, p);	    if ((artfd = open(buff, O_RDONLY)) < 0) {		if (errno != ENOENT)		    (void)fprintf(stderr, SKIPPING,			    Host, buff, strerror(errno));		continue;	    }	}	/* If we need to, get its size. */	if (BytesInArt < 0) {	    if (fstat(artfd, &Sb) < 0) {		(void)fprintf(stderr, SKIPPING, Host, line, strerror(errno));		(void)close(artfd);		continue;	    }	    if (!S_ISREG(Sb.st_mode)) {		(void)fprintf(stderr, SKIPPING, Host, line, "not a file");		(void)close(artfd);		continue;	    }	    BytesInArt = Sb.st_size;	}	/* Have an open article, do we need to open a batch?  This code	 * is here (rather then up before the while loop) so that we	 * can avoid sending an empty batch.  The goto makes the code	 * a bit more clear. */	if (F == NULL) {	    if (GotInterrupt) {		(void)close(artfd);		RequeueAndExit(Cookie, (char *)NULL, 0L);	    }	    if ((F = BATCHstart()) == NULL) {		(void)fprintf(stderr, "batcher %s cant startbatch %d %s\n",			Host, BATCHcount, strerror(errno));		(void)close(artfd);		break;	    }	    if (InitialString && *InitialString) {		(void)fprintf(F, "%s\n", InitialString);		BytesInCB += strlen(InitialString) + 1;		BytesWritten += strlen(InitialString) + 1;	    }	    Cookie = ftell(stdin) - length;	    goto SendIt;	}	/* We're writing a batch, see if adding the current article	 * would exceed the limits. */	if ((ArtsInBatch > 0 && ArtsInCB + 1 >= ArtsInBatch)	 || (BytesInBatch > 0 && BytesInCB + BytesInArt >= BytesInBatch)) {	    if ((BATCHstatus = BATCHclose(F)) != 0) {		if (BATCHstatus == -1)		    (void)fprintf(stderr, "batcher %s cant closebatch %d %s\n",			    Host, BATCHcount, strerror(errno));		else		    (void)fprintf(stderr, "batcher %s batch %d exit %d\n",			    Host, BATCHcount, BATCHstatus);		(void)close(artfd);		break;	    }	    ArtsInCB = 0;	    BytesInCB = 0;	    /* See if we can start a new batch. */	    if ((MaxBatches > 0 && BATCHcount >= MaxBatches)	     || (MaxBytes > 0 && BytesWritten + BytesInArt >= MaxBytes)	     || (MaxArts > 0 && ArtsWritten + 1 >= MaxArts)) {		(void)close(artfd);		break;	    }	    if (GotInterrupt) {		(void)close(artfd);		RequeueAndExit(Cookie, line, BytesInArt);	    }	    if ((F = BATCHstart()) == NULL) {		(void)fprintf(stderr, "batcher %s cant startbatch %d %s\n",			Host, BATCHcount, strerror(errno));		(void)close(artfd);		break;	    }	    Cookie = ftell(stdin) - length;	}    SendIt:	/* Now we can start to send the article! */	if (Separator && *Separator) {	    (void)sprintf(buff, Separator, BytesInArt);	    BytesInCB += strlen(buff) + 1;	    BytesWritten += strlen(buff) + 1;	    if (fprintf(F, "%s\n", buff) == EOF || ferror(F)) {		(void)fprintf(stderr, "batcher %s cant write separator %s\n",		    Host, strerror(errno));		(void)close(artfd);		break;	    }	}	/* Write the article.  In case of interrupts, retry the read but	 * not the fwrite because we can't check that reliably and	 * portably. */	while ((i = read(artfd, (POINTER)data, datasize)) > 0 || errno == EINTR)	    if (fwrite((POINTER)data, (SIZE_T)1, (SIZE_T)i, F) != i)	        break;	if (ferror(F)) {	    (void)fprintf(stderr, "batcher %s cant write article %s\n",		    Host, strerror(errno));	    (void)close(artfd);	    break;	}	(void)close(artfd);	/* Update the counts. */	BytesInCB += BytesInArt;	BytesWritten += BytesInArt;	ArtsInCB++;	ArtsWritten++;	if (GotInterrupt) {	    BATCHstatus = BATCHclose(F);	    RequeueAndExit(Cookie, line, BytesInArt);	}    }    if (BATCHopen)	BATCHstatus = BATCHclose(F);    RequeueAndExit(Cookie, (char *)NULL, 0L);    /* NOTREACHED */}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -