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

📄 queue.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted provided * that: (1) source distributions retain this entire copyright notice and * comment, and (2) distributions including binaries display the following * acknowledgement:  ``This product includes software developed by the * University of California, Berkeley and its contributors'' in the * documentation or other materials provided with the distribution and in * all advertising materials mentioning features or use of this software. * Neither the 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */# include "sendmail.h"# include <sys/stat.h># include <sys/dir.h># include <signal.h># include <errno.h># include <pwd.h># ifndef QUEUESCCSID(@(#)queue.c 1.1 92/07/30 SMI (no queueing)); /* from UCB 5.23 3/13/88 */# else QUEUESCCSID(@(#)queue.c 1.1 92/07/30 SMI); /* from UCB 5.23 3/13/88 *//***  Work queue.*/struct work{	char		*w_name;	/* name of control file */	long		w_pri;		/* priority of message, see below */	time_t		w_ctime;	/* creation time of message */	struct work	*w_next;	/* next in queue */};typedef struct work	WORK;WORK	*WorkQ;			/* queue of things to be done *//***  QUEUEUP -- queue a message up for future transmission.****	Parameters:**		e -- the envelope to queue up.**		queueall -- if TRUE, queue all addresses, rather than**			just those with the QQUEUEUP flag set.**		announce -- if TRUE, tell when you are queueing up.****	Returns:**		none.****	Side Effects:**		The current request is saved in a control file.*/queueup(e, queueall, announce)	register ENVELOPE *e;	bool queueall;	bool announce;{	char *tf;	char *qf;	char buf[MAXLINE];	register FILE *tfp;	register HDR *h;	register ADDRESS *q;	MAILER nullmailer;	/*	**  Create control file.	*/	tf = newstr(queuename(e, 't'));	tfp = fopen(tf, "w");	if (tfp == NULL)	{		syserr("queueup: cannot create temp file %s", tf);		return;	}	(void) chmod(tf, FileMode);# ifdef DEBUG	if (tTd(40, 1))		printf("queueing %s\n", e->e_id);# endif DEBUG	/*	**  If there is no data file yet, create one.	*/	if (e->e_df == NULL)	{		register FILE *dfp;		extern putbody();		e->e_df = newstr(queuename(e, 'd'));		dfp = fopen(e->e_df, "w");		if (dfp == NULL)		{			syserr("queueup: cannot create %s", e->e_df);			(void) fclose(tfp);			return;		}		(void) chmod(e->e_df, FileMode);		(*e->e_putbody)(dfp, ProgMailer, e);		(void) fclose(dfp);		e->e_putbody = putbody;	}	/*	**  Output future work requests.	**	Priority and creation time should be first, since	**	they are required by orderq.	*/	/* output message priority */	fprintf(tfp, "P%ld\n", e->e_msgpriority);	/* output creation time */	fprintf(tfp, "T%ld\n", e->e_ctime);	/* output name of data file */	fprintf(tfp, "D%s\n", e->e_df);	/* message from envelope, if it exists */	if (e->e_message != NULL)		fprintf(tfp, "M%s\n", e->e_message);	/* output name of sender */	fprintf(tfp, "S%s\n", e->e_from.q_paddr);	/* output list of recipient addresses */	for (q = e->e_sendqueue; q != NULL; q = q->q_next)	{		if (queueall ? !bitset(QDONTSEND, q->q_flags) :			       bitset(QQUEUEUP, q->q_flags))		{			char *ctluser, *getctluser();			if ((ctluser = getctluser(q)) != NULL)				fprintf(tfp, "C%s\n", ctluser);			fprintf(tfp, "R%s\n", q->q_paddr);			if (announce)			{				e->e_to = q->q_paddr;				message(Arpa_Info, "queued");				if (LogLevel > 4)					logdelivery("queued");				e->e_to = NULL;			}#ifdef DEBUG			if (tTd(40, 1))			{				printf("queueing ");				printaddr(q, FALSE);			}#endif		}	}	/* output list of error recipients */	for (q = e->e_errorqueue; q != NULL; q = q->q_next)	{		if (!bitset(QDONTSEND, q->q_flags))		{			char *ctluser, *getctluser();			if ((ctluser = getctluser(q)) != NULL)				fprintf(tfp, "C%s\n", ctluser);			fprintf(tfp, "E%s\n", q->q_paddr);		}	}	/*	**  Output headers for this message.	**	Expand macros completely here.  Queue run will deal with	**	everything as absolute headers.	**		All headers that must be relative to the recipient	**		can be cracked later.	**	We set up a "null mailer" -- i.e., a mailer that will have	**	no effect on the addresses as they are output.	*/	bzero((char *) &nullmailer, sizeof nullmailer);	nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1;	nullmailer.m_eol = "\n";	nullmailer.m_argvsize = 10000;	define('g', "\001f", e);	for (h = e->e_header; h != NULL; h = h->h_link)	{		extern bool bitzerop();				/* don't output null headers */		if (h->h_value == NULL || h->h_value[0] == '\0')			continue;		/* don't output resent headers on non-resent messages */		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))			continue;		/* output this header */		fprintf(tfp, "H");		/* if conditional, output the set of conditions */		if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))		{			int j;			(void) putc('?', tfp);			for (j = '\0'; j <= '\177'; j++)				if (bitnset(j, h->h_mflags))					(void) putc(j, tfp);			(void) putc('?', tfp);		}		/* output the header: expand macros, convert addresses */		if (bitset(H_DEFAULT, h->h_flags))		{			(void) expand(h->h_value, buf, &buf[sizeof buf], e);			fprintf(tfp, "%s: %s\n", h->h_field, buf);		}		else if (bitset(H_FROM|H_RCPT, h->h_flags))		{			commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags),				 &nullmailer);		}		else			fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);	}	/*	**  Clean up.	*/	(void) fclose(tfp);	qf = queuename(e, 'q');	if (tf != NULL)	{		(void) unlink(qf);		if (rename(tf, qf) < 0)			syserr("cannot unlink(%s, %s), df=%s", tf, qf, e->e_df);		errno = 0;	}# ifdef LOG	/* save log info */	if (LogLevel > 15)		syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);# endif LOG}/***  checkpoint -- rewrite the qf file to reflect the updated queue of**	recipients.  WARNING: This function assumes that the recipient**	lines are all at the END of the queue files, after all other lines.**		"others" points to the list of recipients that have NOT been**			processed yet.  We save any already processed **			recipients that have been marked for queuing, plus**			all the non-processed recipients except those that**			have already been delivered to.**/checkpoint(e,others)    ENVELOPE *e;    ADDRESS *others;  {    register ADDRESS *to;    register FILE *qfp;    char buf[MAXFIELD];    extern char *fgetfolded();    long position;    if (others==NULL) return;    qfp = fopen(queuename(e,'q'),"r+");    if (qfp==NULL) return;    while (fgetfolded(buf, sizeof buf, qfp) != NULL)      {	if (buf[0]=='R') break;        position = ftell(qfp);      }    if (feof(qfp) || ferror(qfp))      {        /*	 * got an error reading the queue file - give up.	 */	 fclose(qfp);	 return;      }    fseek(qfp,position,0);    for (to = e->e_sendqueue; to != NULL && to != others; to = to->q_next)	if (bitset(QQUEUEUP, to->q_flags) )	        fprintf(qfp, "R%s\n", to->q_paddr);    if (to != NULL)        for (; to != NULL; to = to->q_next)	    if (!bitset(QDONTSEND, to->q_flags) || 	         bitset(QQUEUEUP, to->q_flags) )		    fprintf(qfp, "R%s\n", to->q_paddr);    ftruncate(fileno(qfp), ftell(qfp));    fclose(qfp);      e->e_flags |= EF_INQUEUE;  }/***  RUNQUEUE -- run the jobs in the queue.****	Gets the stuff out of the queue in some presumably logical**	order and processes them.****	Parameters:**		forkflag -- TRUE if the queue scanning should be done in**			a child process.  We double-fork so it is not our**			child and we don't have to clean up after it.****	Returns:**		none.****	Side Effects:**		runs things in the mail queue.*/runqueue(forkflag)	bool forkflag;{	extern bool shouldqueue();	/*	**  If no work will ever be selected, don't even bother reading	**  the queue.	*/	if (shouldqueue(-100000000L))	{		if (Verbose)			printf("Skipping queue run -- load average too high\n");		if (forkflag)			return;		finis();	}	/*	**  See if we want to go off and do other useful work.	*/	if (forkflag)	{		int pid;		pid = dofork();		if (pid != 0)		{			extern reapchild();			/* parent -- pick up intermediate zombie */#ifndef SIGCHLD			(void) waitfor(pid);#else SIGCHLD			(void) signal(SIGCHLD, reapchild);#endif SIGCHLD			if (QueueIntvl != 0)				(void) setevent(QueueIntvl, runqueue, TRUE);			return;		}		/* child -- double fork */#ifndef SIGCHLD		if (fork() != 0)			exit(EX_OK);#else SIGCHLD		(void) signal(SIGCHLD, SIG_DFL);#endif SIGCHLD	}	setproctitle("running queue");# ifdef LOG	if (LogLevel > 11)		syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid());# endif LOG	/*	**  Release any resources used by the daemon code.	*/# ifdef DAEMON	clrdaemon();# endif DAEMON	/*	**  Start making passes through the queue.	**	First, read and sort the entire queue.	**	Then, process the work in that order.	**		But if you take too long, start over.	*/	/* order the existing work requests */	(void) orderq(FALSE);	/* process them once at a time */	while (WorkQ != NULL)	{		WORK *w = WorkQ;		WorkQ = WorkQ->w_next;		dowork(w);		free(w->w_name);		free((char *) w);	}	/*	 * Don't let dropenvelope() trash locked queue files!	 */	CurEnv->e_id = NULL;	finis();}/***  ORDERQ -- order the work queue.****	Parameters:**		doall -- if set, include everything in the queue (even**			the jobs that cannot be run because the load**			average is too high).  Otherwise, exclude those**			jobs.****	Returns:**		The number of request in the queue (not necessarily**		the number of requests in WorkQ however).****	Side Effects:**		Sets WorkQ to the queue of available work, in order.*/# define NEED_P		001# define NEED_T		002# define NEED_R		004orderq(doall)	bool doall;{	register struct direct *d;	register WORK *w;	DIR *f;	register int i;	WORK wlist[QUEUESIZE+1];	int wn = -1;	extern workcmpf();	extern int	OnlyRunId;		/* main.c */	extern char	*OnlyRunRecip;		/* main.c */	/* clear out old WorkQ */	for (w = WorkQ; w != NULL; )	{		register WORK *nw = w->w_next;		WorkQ = nw;		free(w->w_name);		free((char *) w);		w = nw;	}	/* open the queue directory */	f = opendir(".");	if (f == NULL)	{		syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);		return (0);	}	/*	**  Read the work directory.	*/	while ((d = readdir(f)) != NULL)	{		FILE *cf;		char lbuf[MAXNAME];		/* is this an interesting entry? */		if (d->d_name[0] != 'q' || d->d_name[1] != 'f')			continue;		/*		** If we're only interested in a particular job, check		** for that one.		*/		if (OnlyRunId) {			if (OnlyRunId != atoi(&d->d_name[4])) {				continue;			}		}		/* yes -- open control file (if not too many files) */		if (++wn >= QUEUESIZE)			continue;		cf = fopen(d->d_name, "r");		if (cf == NULL)		{			/* this may be some random person sending hir msgs */			/* syserr("orderq: cannot open %s", cbuf); */#ifdef DEBUG			if (tTd(41, 2))				printf("orderq: cannot open %s (%d)\n",					d->d_name, errno);#endif DEBUG			errno = 0;			wn--;			continue;		}		w = &wlist[wn];		w->w_name = newstr(d->d_name);		/* make sure jobs in creation don't clog queue */		w->w_pri = 0x7fffffff;		w->w_ctime = 0;		/* extract useful information */		i = NEED_P | NEED_T;		if (OnlyRunRecip != 0)			i |= NEED_R;		while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)		{			extern long atol();			switch (lbuf[0])			{			  case 'P':				w->w_pri = atol(&lbuf[1]);				i &= ~NEED_P;				break;			  case 'T':				w->w_ctime = atol(&lbuf[1]);				i &= ~NEED_T;				break;			  case 'R':				if (i & NEED_R)				{				    register char *sp;				    for (sp = &lbuf[1]; *sp; sp++)				    {					if (strncasecmp(sp, OnlyRunRecip,						strlen(OnlyRunRecip)) == 0) {							i &= ~NEED_R;							break;					}				    }				}			}		}		(void) fclose(cf);		/* If recip name didn't match, don't take this queue entry */		if ( (shouldqueue(wlist[wn].w_pri) && !doall) ||		       (i & NEED_R)!= 0)		{			/* don't even bother sorting this job in */			wn--;		}	}	(void) closedir(f);	wn++;	/*	**  Sort the work directory.	*/	qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf);	/*	**  Convert the work list into canonical form.	**	Should be turning it into a list of envelopes here perhaps.	*/	WorkQ = NULL;	for (i = min(wn, QUEUESIZE); --i >= 0; )	{		w = (WORK *) xalloc(sizeof *w);		w->w_name = wlist[i].w_name;		w->w_pri = wlist[i].w_pri;		w->w_ctime = wlist[i].w_ctime;		w->w_next = WorkQ;		WorkQ = w;	}# ifdef DEBUG	if (tTd(40, 1))	{		for (w = WorkQ; w != NULL; w = w->w_next)			printf("%32s: pri=%ld\n", w->w_name, w->w_pri);	}# endif DEBUG	return (wn);}/***  WORKCMPF -- compare function for ordering work.****	Parameters:**		a -- the first argument.**		b -- the second argument.****	Returns:**		-1 if a < b**		 0 if a == b**		+1 if a > b****	Side Effects:**		none.*/workcmpf(a, b)	register WORK *a;	register WORK *b;{	long pa = a->w_pri + a->w_ctime;	long pb = b->w_pri + b->w_ctime;	if (pa == pb)		return (0);	else if (pa > pb)		return (1);	else		return (-1);}/***  DOWORK -- do a work request.****	Parameters:**		w -- the work request to be satisfied.****	Returns:**		none.****	Side Effects:**		The work request is satisfied if possible.*/staticdowork(w)	register WORK *w;{	ENVELOPE *newenvelope();	extern ENVELOPE BlankEnvelope;

⌨️ 快捷键说明

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