queue.c revision 43730
144603Sdcs/*
244603Sdcs * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
344603Sdcs * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
444603Sdcs * Copyright (c) 1988, 1993
544603Sdcs *	The Regents of the University of California.  All rights reserved.
644603Sdcs *
744603Sdcs * By using this file, you agree to the terms and conditions set
844603Sdcs * forth in the LICENSE file which can be found at the top level of
950477Speter * the sendmail distribution.
1044603Sdcs *
1144603Sdcs */
1244603Sdcs
1344603Sdcs# include "sendmail.h"
1444603Sdcs
15293293Sdteske#ifndef lint
1644603Sdcs#if QUEUE
1765785Sdcsstatic char sccsid[] = "@(#)queue.c	8.211 (Berkeley) 1/25/1999 (with queueing)";
1865785Sdcs#else
19135986Srustatic char sccsid[] = "@(#)queue.c	8.211 (Berkeley) 1/25/1999 (without queueing)";
2044603Sdcs#endif
2197201Sgordon#endif /* not lint */
2297201Sgordon
2397201Sgordon# include <errno.h>
2444603Sdcs# include <dirent.h>
2544603Sdcs
2644603Sdcs# if QUEUE
2744603Sdcs
2844603Sdcs/*
2944603Sdcs**  Work queue.
3044603Sdcs*/
3144603Sdcs
3247171Sdcsstruct work
3347171Sdcs{
34230109Seadler	char		*w_name;	/* name of control file */
3544603Sdcs	char		*w_host;	/* name of recipient host */
3644603Sdcs	bool		w_lock;		/* is message locked? */
37230109Seadler	bool		w_tooyoung;	/* is it too young to run? */
3865939Sdcs	long		w_pri;		/* priority of message, see below */
3944603Sdcs	time_t		w_ctime;	/* creation time of message */
4044603Sdcs	struct work	*w_next;	/* next in queue */
4144603Sdcs};
42293293Sdteske
43256381Smarkmtypedef struct work	WORK;
44256381Smarkm
45256381SmarkmWORK	*WorkQ;			/* queue of things to be done */
46256381Smarkm
47256381Smarkm#define QF_VERSION	2	/* version number of this queue format */
48256381Smarkm
49256381Smarkmextern int orderq __P((bool));
50256381Smarkm/*
51256381Smarkm**  QUEUEUP -- queue a message up for future transmission.
52256381Smarkm**
53289508Strasz**	Parameters:
54289508Strasz**		e -- the envelope to queue up.
55289508Strasz**		announce -- if TRUE, tell when you are queueing up.
56289508Strasz**
57289508Strasz**	Returns:
58289508Strasz**		none.
59289508Strasz**
60289508Strasz**	Side Effects:
61289508Strasz**		The current request are saved in a control file.
62289508Strasz**		The queue file is left locked.
6344603Sdcs*/
6444603Sdcs
6544603Sdcsvoid
66262702Sdteskequeueup(e, announce)
67262702Sdteske	register ENVELOPE *e;
68146421Ssobomax	bool announce;
69146421Ssobomax{
70146421Ssobomax	char *qf;
71172327Sru	register FILE *tfp;
72172327Sru	register HDR *h;
73281843Sdteske	register ADDRESS *q;
74281843Sdteske	int fd;
75281843Sdteske	int i;
76293802Sallanjude	bool newid;
77117090Sbrueffer	register char *p;
78262701Sdteske	MAILER nullmailer;
79227727Smiwi	MCI mcibuf;
80149213Siedowse	char tf[MAXQFNAME];
81148515Sbrian	char buf[MAXLINE];
8254247Sdcs	extern void printctladdr __P((ADDRESS *, FILE *));
83133217Sjmg
8452749Sdcs	/*
8554247Sdcs	**  Create control file.
8654247Sdcs	*/
87224408Srodrigc
88224408Srodrigc	newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
89224408Srodrigc
90224408Srodrigc	/* if newid, queuename will create a locked qf file in e->lockfp */
91224408Srodrigc	strcpy(tf, queuename(e, 't'));
92278602Sian	tfp = e->e_lockfp;
9344603Sdcs	if (tfp == NULL)
9444603Sdcs		newid = FALSE;
9544603Sdcs
9644603Sdcs	/* if newid, just write the qf file directly (instead of tf file) */
9744603Sdcs	if (!newid)
9844603Sdcs	{
99148515Sbrian		/* get a locked tf file */
100148515Sbrian		for (i = 0; i < 128; i++)
101148515Sbrian		{
102148515Sbrian			fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
103148515Sbrian			if (fd < 0)
104148515Sbrian			{
105148515Sbrian				if (errno != EEXIST)
106150469Sru					break;
107148515Sbrian				if (LogLevel > 0 && (i % 32) == 0)
108148515Sbrian					sm_syslog(LOG_ALERT, e->e_id,
109150469Sru						"queueup: cannot create %s, uid=%d: %s",
110150469Sru						tf, geteuid(), errstring(errno));
111148515Sbrian			}
112148515Sbrian			else
113148515Sbrian			{
114226833Spluknet				if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB))
11554265Smsmith					break;
116166486Simp				else if (LogLevel > 0 && (i % 32) == 0)
117166486Simp					sm_syslog(LOG_ALERT, e->e_id,
118166486Simp						"queueup: cannot lock %s: %s",
11944603Sdcs						tf, errstring(errno));
12044603Sdcs				close(fd);
12144603Sdcs			}
12244603Sdcs
12344603Sdcs			if ((i % 32) == 31)
12444603Sdcs			{
125132853Sceri				/* save the old temp file away */
12699332Smini				(void) rename(tf, queuename(e, 'T'));
12799332Smini			}
12899332Smini			else
12999332Smini				sleep(i % 32);
13099332Smini		}
13199332Smini		if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL)
13299332Smini		{
13399332Smini			printopenfds(TRUE);
13499332Smini			syserr("!queueup: cannot create queue temp file %s, uid=%d",
13599332Smini				tf, geteuid());
13686902Srwatson		}
137217689Spluknet	}
138148817Skrion
13999332Smini	if (tTd(40, 1))
140202143Sbrooks		printf("\n>>>>> queueing %s%s >>>>>\n", e->e_id,
14199332Smini			newid ? " (new id)" : "");
142225122Smarck	if (tTd(40, 3))
143225122Smarck	{
144102862Sbrooks		extern void printenvflags __P((ENVELOPE *));
145106335Smini
14644603Sdcs		printf("  e_flags=");
14799332Smini		printenvflags(e);
14844603Sdcs	}
14995524Sdcs	if (tTd(40, 32))
15095524Sdcs	{
151125091Sdes		printf("  sendq=");
152283971Sdteske		printaddr(e->e_sendqueue, TRUE);
15370706Sjhb	}
15470706Sjhb	if (tTd(40, 9))
15570706Sjhb	{
156111749Sharti		printf("  tfp=");
15744603Sdcs		dumpfd(fileno(tfp), TRUE, FALSE);
15844603Sdcs		printf("  lockfp=");
15944603Sdcs		if (e->e_lockfp == NULL)
160293293Sdteske			printf("NULL\n");
161209466Sbrucec		else
162209466Sbrucec			dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
163209466Sbrucec	}
164209466Sbrucec
165209466Sbrucec	/*
166209466Sbrucec	**  If there is no data file yet, create one.
167209466Sbrucec	*/
168209466Sbrucec
169209466Sbrucec	if (!bitset(EF_HAS_DF, e->e_flags))
170209466Sbrucec	{
171209466Sbrucec		register FILE *dfp = NULL;
172209466Sbrucec		char dfname[MAXQFNAME];
173209466Sbrucec		struct stat stbuf;
174209466Sbrucec
175209466Sbrucec		strcpy(dfname, queuename(e, 'd'));
176209466Sbrucec		fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
177209466Sbrucec		if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL)
178209466Sbrucec			syserr("!queueup: cannot create data temp file %s, uid=%d",
179209466Sbrucec				dfname, geteuid());
180209466Sbrucec		if (fstat(fd, &stbuf) < 0)
181209466Sbrucec			e->e_dfino = -1;
182209466Sbrucec		else
183209466Sbrucec		{
184209466Sbrucec			e->e_dfdev = stbuf.st_dev;
185209466Sbrucec			e->e_dfino = stbuf.st_ino;
186209466Sbrucec		}
18744603Sdcs		e->e_flags |= EF_HAS_DF;
18844603Sdcs		bzero(&mcibuf, sizeof mcibuf);
18944603Sdcs		mcibuf.mci_out = dfp;
19044603Sdcs		mcibuf.mci_mailer = FileMailer;
19144603Sdcs		(*e->e_putbody)(&mcibuf, e, NULL);
19244603Sdcs		(void) xfclose(dfp, "queueup dfp", e->e_id);
19377034Sru		e->e_putbody = putbody;
194126455Sdes	}
195161286Sbrueffer
19677162Sru	/*
197135986Sru	**  Output future work requests.
198135986Sru	**	Priority and creation time should be first, since
19963962Ssheldonh	**	they are required by orderq.
20044603Sdcs	*/
201161448Sbrueffer
20277034Sru	/* output queue version number (must be first!) */
203168554Spjd	fprintf(tfp, "V%d\n", QF_VERSION);
20444603Sdcs
20544603Sdcs	/* output creation time */
20644603Sdcs	fprintf(tfp, "T%ld\n", (long) e->e_ctime);
207152307Spjd
208152307Spjd	/* output last delivery time */
209152307Spjd	fprintf(tfp, "K%ld\n", (long) e->e_dtime);
210152307Spjd
211152309Spjd	/* output number of delivery attempts */
212152307Spjd	fprintf(tfp, "N%d\n", e->e_ntries);
213152307Spjd
214182194Smatteo	/* output message priority */
215152307Spjd	fprintf(tfp, "P%ld\n", e->e_msgpriority);
216152309Spjd
217166003Smaxim	/* output inode number of data file */
218152307Spjd	/* XXX should probably include device major/minor too */
219202437Strasz	if (e->e_dfino != -1)
220152307Spjd	{
221152307Spjd		if (sizeof e->e_dfino > sizeof(long))
222152307Spjd			fprintf(tfp, "I%d/%d/%s\n",
223152307Spjd				major(e->e_dfdev), minor(e->e_dfdev),
224152309Spjd				quad_to_string(e->e_dfino));
225152307Spjd		else
22644603Sdcs			fprintf(tfp, "I%d/%d/%lu\n",
22744603Sdcs				major(e->e_dfdev), minor(e->e_dfdev),
22844603Sdcs				(unsigned long) e->e_dfino);
229209466Sbrucec	}
230209466Sbrucec
231209466Sbrucec	/* output body type */
232209466Sbrucec	if (e->e_bodytype != NULL)
233209466Sbrucec		fprintf(tfp, "B%s\n", denlstring(e->e_bodytype, TRUE, FALSE));
234209466Sbrucec
235209466Sbrucec#if _FFR_SAVE_CHARSET
236209466Sbrucec	if (e->e_charset != NULL)
237209466Sbrucec		fprintf(tfp, "X%s\n", denlstring(e->e_charset, TRUE, FALSE));
238209466Sbrucec#endif
239209466Sbrucec
240209466Sbrucec	/* message from envelope, if it exists */
24144603Sdcs	if (e->e_message != NULL)
24244603Sdcs		fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
24344603Sdcs
24444603Sdcs	/* send various flag bits through */
24544603Sdcs	p = buf;
24644603Sdcs	if (bitset(EF_WARNING, e->e_flags))
24744603Sdcs		*p++ = 'w';
24844603Sdcs	if (bitset(EF_RESPONSE, e->e_flags))
24944603Sdcs		*p++ = 'r';
25044603Sdcs	if (bitset(EF_HAS8BIT, e->e_flags))
25144603Sdcs		*p++ = '8';
25244603Sdcs	if (bitset(EF_DELETE_BCC, e->e_flags))
25344603Sdcs		*p++ = 'b';
25444603Sdcs	if (bitset(EF_RET_PARAM, e->e_flags))
25544603Sdcs		*p++ = 'd';
25644603Sdcs	if (bitset(EF_NO_BODY_RETN, e->e_flags))
257197518Sbz		*p++ = 'n';
25847173Sdcs	*p++ = '\0';
25947173Sdcs	if (buf[0] != '\0')
26044603Sdcs		fprintf(tfp, "F%s\n", buf);
26144603Sdcs
26244603Sdcs	/* $r and $s and $_ macro values */
26344603Sdcs	if ((p = macvalue('r', e)) != NULL)
26444603Sdcs		fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE));
26544603Sdcs	if ((p = macvalue('s', e)) != NULL)
26644603Sdcs		fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE));
267166005Smaxim	if ((p = macvalue('_', e)) != NULL)
268166005Smaxim		fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE));
269195892Sbz
270106335Smini	/* output name of sender */
271106335Smini	if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
272106335Smini		p = e->e_sender;
273106335Smini	else
274106335Smini		p = e->e_from.q_paddr;
27544603Sdcs	fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
276106335Smini
27744603Sdcs	/* output ESMTP-supplied "original" information */
278126263Smlaier	if (e->e_envid != NULL)
27944603Sdcs		fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE));
28044603Sdcs
28144603Sdcs	/* output list of recipient addresses */
28247175Sdcs	printctladdr(NULL, NULL);
28347175Sdcs	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
28447175Sdcs	{
285218815Sdanger		if (bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))
28654020Sdcs		{
287228576Sglebius#if XDEBUG
288183592Sstas			if (bitset(QQUEUEUP, q->q_flags))
289179106Syongari				sm_syslog(LOG_DEBUG, e->e_id,
290193880Syongari					"dropenvelope: q_flags = %x, paddr = %s",
291184870Syongari					q->q_flags, q->q_paddr);
29255992Swpaul#endif
293148798Skrion			continue;
294148817Skrion		}
295148817Skrion		printctladdr(q, tfp);
296161286Sbrueffer		if (q->q_orcpt != NULL)
297135986Sru			fprintf(tfp, "Q%s\n",
298161286Sbrueffer				denlstring(q->q_orcpt, TRUE, FALSE));
299218815Sdanger		putc('R', tfp);
300209466Sbrucec		if (bitset(QPRIMARY, q->q_flags))
301204328Sweongyo			putc('P', tfp);
302219647Sdavidch		if (bitset(QHASNOTIFY, q->q_flags))
303194246Smarius			putc('N', tfp);
304106330Smini		if (bitset(QPINGONSUCCESS, q->q_flags))
305148817Skrion			putc('S', tfp);
306148817Skrion		if (bitset(QPINGONFAILURE, q->q_flags))
307209466Sbrucec			putc('F', tfp);
30855017Swpaul		if (bitset(QPINGONDELAY, q->q_flags))
309161286Sbrueffer			putc('D', tfp);
310166005Smaxim		putc(':', tfp);
311166005Smaxim		fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
312161286Sbrueffer		if (announce)
313115054Smurray		{
314106330Smini			e->e_to = q->q_paddr;
315207630Sdelphij			message("queued");
316161286Sbrueffer			if (LogLevel > 8)
317209466Sbrucec				logdelivery(q->q_mailer, NULL, "queued",
318166005Smaxim					    NULL, (time_t) 0, e);
319166005Smaxim			e->e_to = NULL;
32054019Sdcs		}
321158569Smarius		if (tTd(40, 1))
322209466Sbrucec		{
323158569Smarius			printf("queueing ");
324115054Smurray			printaddr(q, FALSE);
325177693Sbrueffer		}
326161286Sbrueffer	}
327166005Smaxim
328166005Smaxim	/*
329209466Sbrucec	**  Output headers for this message.
330161449Sbrueffer	**	Expand macros completely here.  Queue run will deal with
331177693Sbrueffer	**	everything as absolute headers.
332179343Syongari	**		All headers that must be relative to the recipient
333218815Sdanger	**		can be cracked later.
334158569Smarius	**	We set up a "null mailer" -- i.e., a mailer that will have
335166005Smaxim	**	no effect on the addresses as they are output.
336166005Smaxim	*/
337177990Sweongyo
338177990Sweongyo	bzero((char *) &nullmailer, sizeof nullmailer);
339165145Syongari	nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
340161449Sbrueffer			nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
341161286Sbrueffer	nullmailer.m_eol = "\n";
342161448Sbrueffer	bzero(&mcibuf, sizeof mcibuf);
343161286Sbrueffer	mcibuf.mci_mailer = &nullmailer;
344148817Skrion	mcibuf.mci_out = tfp;
345177693Sbrueffer
346209466Sbrucec	define('g', "\201f", e);
347106335Smini	for (h = e->e_header; h != NULL; h = h->h_link)
348177693Sbrueffer	{
349135986Sru		extern bool bitzerop __P((BITMAP));
35055017Swpaul
351148817Skrion		if (h->h_value == NULL)
352209466Sbrucec			continue;
353209466Sbrucec
354182912Sjhb		/* don't output resent headers on non-resent messages */
35554019Sdcs		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
356207630Sdelphij			continue;
35754019Sdcs
358161286Sbrueffer		/* expand macros; if null, don't output header at all */
359106330Smini		if (bitset(H_DEFAULT, h->h_flags))
360161286Sbrueffer		{
361161286Sbrueffer			(void) expand(h->h_value, buf, sizeof buf, e);
36254019Sdcs			if (buf[0] == '\0')
36354019Sdcs				continue;
364161286Sbrueffer		}
365106335Smini
366135986Sru		/* output this header */
367216829Syongari		fprintf(tfp, "H");
368190789Sweongyo
369148817Skrion		/* if conditional, output the set of conditions */
370181581Sweongyo		if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
371177693Sbrueffer		{
372187614Sweongyo			int j;
37354019Sdcs
374106330Smini			(void) putc('?', tfp);
37554019Sdcs			for (j = '\0'; j <= '\177'; j++)
37655992Swpaul				if (bitnset(j, h->h_mflags))
377177693Sbrueffer					(void) putc(j, tfp);
378106330Smini			(void) putc('?', tfp);
37954019Sdcs		}
380209466Sbrucec
38147175Sdcs		/* output the header: expand macros, convert addresses */
382293293Sdteske		if (bitset(H_DEFAULT, h->h_flags))
38347175Sdcs		{
38474212Sjhb			fprintf(tfp, "%s: %s\n",
38574212Sjhb				h->h_field,
38674212Sjhb				denlstring(buf, FALSE, TRUE));
38774212Sjhb		}
38874212Sjhb		else if (bitset(H_FROM|H_RCPT, h->h_flags))
38974212Sjhb		{
39074212Sjhb			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
39174212Sjhb			FILE *savetrace = TrafficLogFile;
39274212Sjhb
393135986Sru			TrafficLogFile = NULL;
394135986Sru
39574212Sjhb			if (bitset(H_FROM, h->h_flags))
396135986Sru				oldstyle = FALSE;
39774212Sjhb
398135986Sru			commaize(h, h->h_value, oldstyle, &mcibuf, e);
399135986Sru
40074212Sjhb			TrafficLogFile = savetrace;
401135986Sru		}
40274212Sjhb		else
403135986Sru		{
40474212Sjhb			fprintf(tfp, "%s: %s\n",
405135986Sru				h->h_field,
40674212Sjhb				denlstring(h->h_value, FALSE, TRUE));
407166005Smaxim		}
408166005Smaxim	}
409166004Smaxim
41074212Sjhb	/*
41174212Sjhb	**  Clean up.
41274212Sjhb	**
41374212Sjhb	**	Write a terminator record -- this is to prevent
41474212Sjhb	**	scurrilous crackers from appending any data.
41574212Sjhb	*/
416166005Smaxim
417166005Smaxim	fprintf(tfp, ".\n");
418135986Sru
41974212Sjhb	if (fflush(tfp) < 0 ||
420166005Smaxim	    (SuperSafe && fsync(fileno(tfp)) < 0) ||
421166005Smaxim	    ferror(tfp))
42274212Sjhb	{
423135986Sru		if (newid)
42474212Sjhb			syserr("!552 Error writing control file %s", tf);
425293293Sdteske		else
42674212Sjhb			syserr("!452 Error writing control file %s", tf);
42774212Sjhb	}
42874212Sjhb
42974212Sjhb	if (!newid)
430132248Stanimura	{
43174212Sjhb		/* rename (locked) tf to be (locked) qf */
432135986Sru		qf = queuename(e, 'q');
433152979Sariff		if (rename(tf, qf) < 0)
43474212Sjhb			syserr("cannot rename(%s, %s), uid=%d",
435135986Sru				tf, qf, geteuid());
43674212Sjhb
43774212Sjhb		/* close and unlock old (locked) qf */
43874212Sjhb		if (e->e_lockfp != NULL)
439160709Sache			(void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
440161286Sbrueffer		e->e_lockfp = tfp;
441162890Snetchild	}
442135986Sru	else
44374212Sjhb		qf = tf;
44474212Sjhb	errno = 0;
445162934Sariff	e->e_flags |= EF_INQUEUE;
44688253Sjim
44774212Sjhb	/* save log info */
44874212Sjhb	if (LogLevel > 79)
44974212Sjhb		sm_syslog(LOG_DEBUG, e->e_id, "queueup, qf=%s", qf);
45074212Sjhb
451135986Sru	if (tTd(40, 1))
452135986Sru		printf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
45374212Sjhb	return;
45474212Sjhb}
455162890Snetchild
45674212Sjhbvoid
457102011Sorionprintctladdr(a, tfp)
45874212Sjhb	register ADDRESS *a;
459135986Sru	FILE *tfp;
460107175Sdcs{
46174212Sjhb	char *uname;
462293293Sdteske	register ADDRESS *q;
46374212Sjhb	uid_t uid;
46453243Sn_hibma	gid_t gid;
46553243Sn_hibma	static ADDRESS *lastctladdr = NULL;
46653243Sn_hibma	static uid_t lastuid;
46753548Sn_hibma
46859895Sn_hibma	/* initialization */
46953548Sn_hibma	if (a == NULL || a->q_alias == NULL || tfp == NULL)
470209466Sbrucec	{
47191609Salfred		if (lastctladdr != NULL && tfp != NULL)
47253548Sn_hibma			fprintf(tfp, "C\n");
47353548Sn_hibma		lastctladdr = NULL;
47453548Sn_hibma		lastuid = 0;
47553548Sn_hibma		return;
47653548Sn_hibma	}
477209466Sbrucec
47867955Sn_hibma	/* find the active uid */
479209466Sbrucec	q = getctladdr(a);
480209466Sbrucec	if (q == NULL)
481209466Sbrucec	{
48255162Swpaul		uname = NULL;
483115054Smurray		uid = 0;
484209466Sbrucec		gid = 0;
48555944Swpaul	}
48655429Swpaul	else
487209466Sbrucec	{
488177990Sweongyo		uname = q->q_ruser != NULL ? q->q_ruser : q->q_user;
489209466Sbrucec		uid = q->q_uid;
490209466Sbrucec		gid = q->q_gid;
491177990Sweongyo	}
492177990Sweongyo	a = a->q_alias;
493135986Sru
49453243Sn_hibma	/* check to see if this is the same as last time */
495293293Sdteske	if (lastctladdr != NULL && uid == lastuid &&
49653243Sn_hibma	    strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
49744603Sdcs		return;
49844603Sdcs	lastuid = uid;
49944603Sdcs	lastctladdr = a;
500209466Sbrucec
50147890Sroger	if (uid == 0 || uname == NULL || uname[0] == '\0')
50261757Smjacob		fprintf(tfp, "C");
50374212Sjhb	else
50474263Sjhb		fprintf(tfp, "C%s:%ld:%ld",
505192247Sbrueffer			denlstring(uname, TRUE, FALSE), (long) uid, (long) gid);
50674263Sjhb	fprintf(tfp, ":%s\n", denlstring(a->q_paddr, TRUE, FALSE));
507209466Sbrucec}
508209466Sbrucec/*
509209466Sbrucec**  RUNQUEUE -- run the jobs in the queue.
51065689Smarkm**
511128280Scperciva**	Gets the stuff out of the queue in some presumably logical
512181297Srpaulo**	order and processes them.
513209466Sbrucec**
514209466Sbrucec**	Parameters:
515209466Sbrucec**		forkflag -- TRUE if the queue scanning should be done in
516189872Sdchagin**			a child process.  We double-fork so it is not our
517212861Snork**			child and we don't have to clean up after it.
518232614Sbz**		verbose -- if TRUE, print out status information.
51944603Sdcs**
520293293Sdteske**	Returns:
52144603Sdcs**		TRUE if the queue run successfully began.
52286133Siwasaki**
52386133Siwasaki**	Side Effects:
52486133Siwasaki**		runs things in the mail queue.
52586133Siwasaki*/
52686133Siwasaki
52786133SiwasakiENVELOPE	QueueEnvelope;		/* the queue run envelope */
52886133Siwasakiextern int	get_num_procs_online __P((void));
529126453Sdes
53086133Siwasakibool
531293293Sdteskerunqueue(forkflag, verbose)
53286133Siwasaki	bool forkflag;
533293293Sdteske	bool verbose;
534101187Srwatson{
535101187Srwatson	register ENVELOPE *e;
536101187Srwatson	int njobs;
537101187Srwatson	int sequenceno = 0;
538101187Srwatson	time_t current_la_time;
539101187Srwatson	extern ENVELOPE BlankEnvelope;
540101187Srwatson	extern void clrdaemon __P((void));
541101187Srwatson	extern void runqueueevent __P((void));
542101187Srwatson
543101187Srwatson	DoQueueRun = FALSE;
544293293Sdteske
545101187Srwatson	/*
54644603Sdcs	**  If no work will ever be selected, don't even bother reading
54744603Sdcs	**  the queue.
54844603Sdcs	*/
54944603Sdcs
55044603Sdcs	CurrentLA = getla();	/* get load average */
55144603Sdcs	current_la_time = curtime();
55244603Sdcs
55344603Sdcs	if (shouldqueue(WkRecipFact, current_la_time))
55444603Sdcs	{
55544603Sdcs		char *msg = "Skipping queue run -- load average too high";
556
557		if (verbose)
558			message("458 %s\n", msg);
559		if (LogLevel > 8)
560			sm_syslog(LOG_INFO, NOQID,
561				"runqueue: %s",
562				msg);
563		if (forkflag && QueueIntvl != 0)
564			(void) setevent(QueueIntvl, runqueueevent, 0);
565		return FALSE;
566	}
567
568	/*
569	**  See if we already have too many children.
570	*/
571
572	if (forkflag && QueueIntvl != 0 &&
573	    MaxChildren > 0 && CurChildren >= MaxChildren)
574	{
575		(void) setevent(QueueIntvl, runqueueevent, 0);
576		return FALSE;
577	}
578
579	/*
580	**  See if we want to go off and do other useful work.
581	*/
582
583	if (forkflag)
584	{
585		pid_t pid;
586		extern SIGFUNC_DECL intsig __P((int));
587		extern SIGFUNC_DECL reapchild __P((int));
588
589		blocksignal(SIGCHLD);
590		(void) setsignal(SIGCHLD, reapchild);
591
592		pid = dofork();
593		if (pid == -1)
594		{
595			const char *msg = "Skipping queue run -- fork() failed";
596			const char *err = errstring(errno);
597
598			if (verbose)
599				message("458 %s: %s\n", msg, err);
600			if (LogLevel > 8)
601				sm_syslog(LOG_INFO, NOQID,
602					"runqueue: %s: %s",
603					msg, err);
604			if (QueueIntvl != 0)
605				(void) setevent(QueueIntvl, runqueueevent, 0);
606			(void) releasesignal(SIGCHLD);
607			return FALSE;
608		}
609		if (pid != 0)
610		{
611			/* parent -- pick up intermediate zombie */
612			(void) blocksignal(SIGALRM);
613			proc_list_add(pid, "Queue runner");
614			(void) releasesignal(SIGALRM);
615			releasesignal(SIGCHLD);
616			if (QueueIntvl != 0)
617				(void) setevent(QueueIntvl, runqueueevent, 0);
618			return TRUE;
619		}
620		/* child -- double fork and clean up signals */
621		clrcontrol();
622		proc_list_clear();
623
624		/* Add parent process as first child item */
625		proc_list_add(getpid(), "Queue runner child process");
626		releasesignal(SIGCHLD);
627		(void) setsignal(SIGCHLD, SIG_DFL);
628		(void) setsignal(SIGHUP, intsig);
629	}
630
631	sm_setproctitle(TRUE, "running queue: %s", QueueDir);
632
633	if (LogLevel > 69)
634		sm_syslog(LOG_DEBUG, NOQID,
635			"runqueue %s, pid=%d, forkflag=%d",
636			QueueDir, getpid(), forkflag);
637
638	/*
639	**  Release any resources used by the daemon code.
640	*/
641
642# if DAEMON
643	clrdaemon();
644# endif /* DAEMON */
645
646	/* force it to run expensive jobs */
647	NoConnect = FALSE;
648
649	/* drop privileges */
650	if (geteuid() == (uid_t) 0)
651		(void) drop_privileges(FALSE);
652
653	/*
654	**  Create ourselves an envelope
655	*/
656
657	CurEnv = &QueueEnvelope;
658	e = newenvelope(&QueueEnvelope, CurEnv);
659	e->e_flags = BlankEnvelope.e_flags;
660
661	/* make sure we have disconnected from parent */
662	if (forkflag)
663	{
664		disconnect(1, e);
665		QuickAbort = FALSE;
666	}
667
668	/*
669	**  Make sure the alias database is open.
670	*/
671
672	initmaps(FALSE, e);
673
674	/*
675	**  If we are running part of the queue, always ignore stored
676	**  host status.
677	*/
678
679	if (QueueLimitId != NULL || QueueLimitSender != NULL ||
680	    QueueLimitRecipient != NULL)
681	{
682		IgnoreHostStatus = TRUE;
683		MinQueueAge = 0;
684	}
685
686	/*
687	**  Start making passes through the queue.
688	**	First, read and sort the entire queue.
689	**	Then, process the work in that order.
690	**		But if you take too long, start over.
691	*/
692
693	/* order the existing work requests */
694	njobs = orderq(FALSE);
695
696	/* process them once at a time */
697	while (WorkQ != NULL)
698	{
699		WORK *w = WorkQ;
700
701		WorkQ = WorkQ->w_next;
702		e->e_to = NULL;
703
704		/*
705		**  Ignore jobs that are too expensive for the moment.
706		**
707		**	Get new load average every 30 seconds.
708		*/
709
710		if (current_la_time < curtime() - 30)
711		{
712			CurrentLA = getla();
713			current_la_time = curtime();
714		}
715		if (shouldqueue(WkRecipFact, current_la_time))
716		{
717			char *msg = "Aborting queue run: load average too high";
718
719			if (Verbose)
720				message("%s", msg);
721			if (LogLevel > 8)
722				sm_syslog(LOG_INFO, NOQID,
723					"runqueue: %s",
724					msg);
725			break;
726		}
727		sequenceno++;
728		if (shouldqueue(w->w_pri, w->w_ctime))
729		{
730			if (Verbose)
731				message("");
732			if (QueueSortOrder == QS_BYPRIORITY)
733			{
734				if (Verbose)
735					message("Skipping %s (sequence %d of %d) and flushing rest of queue",
736						w->w_name + 2,
737						sequenceno,
738						njobs);
739				if (LogLevel > 8)
740					sm_syslog(LOG_INFO, NOQID,
741						"runqueue: Flushing queue from %s (pri %ld, LA %d, %d of %d)",
742						w->w_name + 2,
743						w->w_pri,
744						CurrentLA,
745						sequenceno,
746						njobs);
747				break;
748			}
749			else if (Verbose)
750				message("Skipping %s (sequence %d of %d)",
751					w->w_name + 2, sequenceno, njobs);
752		}
753		else
754		{
755			pid_t pid;
756
757			if (Verbose)
758			{
759				message("");
760				message("Running %s (sequence %d of %d)",
761					w->w_name + 2, sequenceno, njobs);
762			}
763			pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
764			errno = 0;
765			if (pid != 0)
766				(void) waitfor(pid);
767		}
768		free(w->w_name);
769		if (w->w_host)
770			free(w->w_host);
771		free((char *) w);
772	}
773
774	/* exit without the usual cleanup */
775	e->e_id = NULL;
776	finis(TRUE, ExitStat);
777	/*NOTREACHED*/
778	return TRUE;
779}
780
781
782/*
783**  RUNQUEUEEVENT -- stub for use in setevent
784*/
785
786void
787runqueueevent()
788{
789	DoQueueRun = TRUE;
790}
791/*
792**  ORDERQ -- order the work queue.
793**
794**	Parameters:
795**		doall -- if set, include everything in the queue (even
796**			the jobs that cannot be run because the load
797**			average is too high).  Otherwise, exclude those
798**			jobs.
799**
800**	Returns:
801**		The number of request in the queue (not necessarily
802**		the number of requests in WorkQ however).
803**
804**	Side Effects:
805**		Sets WorkQ to the queue of available work, in order.
806*/
807
808# define NEED_P		001
809# define NEED_T		002
810# define NEED_R		004
811# define NEED_S		010
812
813static WORK	*WorkList = NULL;
814static int	WorkListSize = 0;
815
816int
817orderq(doall)
818	bool doall;
819{
820	register struct dirent *d;
821	register WORK *w;
822	register char *p;
823	DIR *f;
824	register int i;
825	int wn = -1;
826	int wc;
827	QUEUE_CHAR *check;
828
829	if (tTd(41, 1))
830	{
831		printf("orderq:\n");
832
833		check = QueueLimitId;
834		while (check != NULL)
835		{
836			printf("\tQueueLimitId = %s\n",
837			       check->queue_match);
838			check = check->queue_next;
839		}
840
841		check = QueueLimitSender;
842		while (check != NULL)
843		{
844			printf("\tQueueLimitSender = %s\n",
845			       check->queue_match);
846			check = check->queue_next;
847		}
848
849		check = QueueLimitRecipient;
850		while (check != NULL)
851		{
852			printf("\tQueueLimitRecipient = %s\n",
853			       check->queue_match);
854			check = check->queue_next;
855		}
856	}
857
858	/* clear out old WorkQ */
859	for (w = WorkQ; w != NULL; )
860	{
861		register WORK *nw = w->w_next;
862
863		WorkQ = nw;
864		free(w->w_name);
865		if (w->w_host)
866			free(w->w_host);
867		free((char *) w);
868		w = nw;
869	}
870
871	/* open the queue directory */
872	f = opendir(".");
873	if (f == NULL)
874	{
875		syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
876		return (0);
877	}
878
879	/*
880	**  Read the work directory.
881	*/
882
883	while ((d = readdir(f)) != NULL)
884	{
885		FILE *cf;
886		int qfver = 0;
887		char lbuf[MAXNAME + 1];
888		extern bool strcontainedin __P((char *, char *));
889
890		if (tTd(41, 50))
891			printf("orderq: checking %s\n", d->d_name);
892
893		/* is this an interesting entry? */
894		if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
895			continue;
896
897		if (strlen(d->d_name) > MAXQFNAME)
898		{
899			if (Verbose)
900				printf("orderq: %s too long, %d max characters\n",
901					d->d_name, MAXQFNAME);
902			if (LogLevel > 0)
903				sm_syslog(LOG_ALERT, NOQID,
904					"orderq: %s too long, %d max characters",
905					d->d_name, MAXQFNAME);
906			continue;
907		}
908
909		check = QueueLimitId;
910		while (check != NULL)
911		{
912			if (strcontainedin(check->queue_match, d->d_name))
913				break;
914			else
915				check = check->queue_next;
916		}
917		if (QueueLimitId != NULL && check == NULL)
918			continue;
919
920#ifdef PICKY_QF_NAME_CHECK
921		/*
922		**  Check queue name for plausibility.  This handles
923		**  both old and new type ids.
924		*/
925
926		p = d->d_name + 2;
927		if (isupper(p[0]) && isupper(p[2]))
928			p += 3;
929		else if (isupper(p[1]))
930			p += 2;
931		else
932			p = d->d_name;
933		for (i = 0; isdigit(*p); p++)
934			i++;
935		if (i < 5 || *p != '\0')
936		{
937			if (Verbose)
938				printf("orderq: bogus qf name %s\n", d->d_name);
939			if (LogLevel > 0)
940				sm_syslog(LOG_ALERT, NOQID,
941					"orderq: bogus qf name %s",
942					d->d_name);
943			if (strlen(d->d_name) > (SIZE_T) MAXNAME)
944				d->d_name[MAXNAME] = '\0';
945			strcpy(lbuf, d->d_name);
946			lbuf[0] = 'Q';
947			(void) rename(d->d_name, lbuf);
948			continue;
949		}
950#endif
951
952		/* open control file (if not too many files) */
953		if (++wn >= MaxQueueRun && MaxQueueRun > 0)
954		{
955			if (wn == MaxQueueRun && LogLevel > 0)
956				sm_syslog(LOG_ALERT, NOQID,
957					"WorkList for %s maxed out at %d",
958					QueueDir, MaxQueueRun);
959			continue;
960		}
961		if (wn >= WorkListSize)
962		{
963			extern void grow_wlist __P((void));
964
965			grow_wlist();
966			if (wn >= WorkListSize)
967				continue;
968		}
969
970		cf = fopen(d->d_name, "r");
971		if (cf == NULL)
972		{
973			/* this may be some random person sending hir msgs */
974			/* syserr("orderq: cannot open %s", cbuf); */
975			if (tTd(41, 2))
976				printf("orderq: cannot open %s: %s\n",
977					d->d_name, errstring(errno));
978			errno = 0;
979			wn--;
980			continue;
981		}
982		w = &WorkList[wn];
983		w->w_name = newstr(d->d_name);
984		w->w_host = NULL;
985		w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
986		w->w_tooyoung = FALSE;
987
988		/* make sure jobs in creation don't clog queue */
989		w->w_pri = 0x7fffffff;
990		w->w_ctime = 0;
991
992		/* extract useful information */
993		i = NEED_P | NEED_T;
994		if (QueueLimitSender != NULL)
995			i |= NEED_S;
996		if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL)
997			i |= NEED_R;
998		while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
999		{
1000			int c;
1001			time_t age;
1002			extern bool strcontainedin __P((char *, char *));
1003
1004			p = strchr(lbuf, '\n');
1005			if (p != NULL)
1006				*p = '\0';
1007			else
1008			{
1009				/* flush rest of overly long line */
1010				while ((c = getc(cf)) != EOF && c != '\n')
1011					continue;
1012			}
1013
1014			switch (lbuf[0])
1015			{
1016			  case 'V':
1017				qfver = atoi(&lbuf[1]);
1018				break;
1019
1020			  case 'P':
1021				w->w_pri = atol(&lbuf[1]);
1022				i &= ~NEED_P;
1023				break;
1024
1025			  case 'T':
1026				w->w_ctime = atol(&lbuf[1]);
1027				i &= ~NEED_T;
1028				break;
1029
1030			  case 'R':
1031				if (w->w_host == NULL &&
1032				    (p = strrchr(&lbuf[1], '@')) != NULL)
1033					w->w_host = newstr(&p[1]);
1034				if (QueueLimitRecipient == NULL)
1035				{
1036					i &= ~NEED_R;
1037					break;
1038				}
1039				if (qfver > 0)
1040				{
1041					p = strchr(&lbuf[1], ':');
1042					if (p == NULL)
1043						p = &lbuf[1];
1044				}
1045				else
1046					p = &lbuf[1];
1047				check = QueueLimitRecipient;
1048				while (check != NULL)
1049				{
1050					if (strcontainedin(check->queue_match,
1051							   p))
1052						break;
1053					else
1054						check = check->queue_next;
1055				}
1056				if (check != NULL)
1057					i &= ~NEED_R;
1058				break;
1059
1060			  case 'S':
1061				  check = QueueLimitSender;
1062				  while (check != NULL)
1063				  {
1064					  if (strcontainedin(check->queue_match,
1065							     &lbuf[1]))
1066						  break;
1067					  else
1068						  check = check->queue_next;
1069				  }
1070				  if (check != NULL)
1071					  i &= ~NEED_S;
1072				break;
1073
1074			  case 'K':
1075				age = curtime() - (time_t) atol(&lbuf[1]);
1076				if (age >= 0 && MinQueueAge > 0 &&
1077				    age < MinQueueAge)
1078					w->w_tooyoung = TRUE;
1079				break;
1080
1081			  case 'N':
1082				if (atol(&lbuf[1]) == 0)
1083					w->w_tooyoung = FALSE;
1084				break;
1085			}
1086		}
1087		(void) fclose(cf);
1088
1089		if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
1090		    bitset(NEED_R|NEED_S, i))
1091		{
1092			/* don't even bother sorting this job in */
1093			if (tTd(41, 49))
1094				printf("skipping %s (%x)\n", w->w_name, i);
1095			free(w->w_name);
1096			if (w->w_host)
1097				free(w->w_host);
1098			wn--;
1099		}
1100	}
1101	(void) closedir(f);
1102	wn++;
1103
1104	wc = min(wn, WorkListSize);
1105	if (wc > MaxQueueRun && MaxQueueRun > 0)
1106		wc = MaxQueueRun;
1107
1108	if (QueueSortOrder == QS_BYHOST)
1109	{
1110		extern int workcmpf1();
1111		extern int workcmpf2();
1112
1113		/*
1114		**  Sort the work directory for the first time,
1115		**  based on host name, lock status, and priority.
1116		*/
1117
1118		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
1119
1120		/*
1121		**  If one message to host is locked, "lock" all messages
1122		**  to that host.
1123		*/
1124
1125		i = 0;
1126		while (i < wc)
1127		{
1128			if (!WorkList[i].w_lock)
1129			{
1130				i++;
1131				continue;
1132			}
1133			w = &WorkList[i];
1134			while (++i < wc)
1135			{
1136				extern int sm_strcasecmp __P((char *, char *));
1137
1138				if (WorkList[i].w_host == NULL &&
1139				    w->w_host == NULL)
1140					WorkList[i].w_lock = TRUE;
1141				else if (WorkList[i].w_host != NULL &&
1142					 w->w_host != NULL &&
1143					 sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0)
1144					WorkList[i].w_lock = TRUE;
1145				else
1146					break;
1147			}
1148		}
1149
1150		/*
1151		**  Sort the work directory for the second time,
1152		**  based on lock status, host name, and priority.
1153		*/
1154
1155		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
1156	}
1157	else if (QueueSortOrder == QS_BYTIME)
1158	{
1159		extern int workcmpf3();
1160
1161		/*
1162		**  Simple sort based on submission time only.
1163		*/
1164
1165		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
1166	}
1167	else
1168	{
1169		extern int workcmpf0();
1170
1171		/*
1172		**  Simple sort based on queue priority only.
1173		*/
1174
1175		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
1176	}
1177
1178	/*
1179	**  Convert the work list into canonical form.
1180	**	Should be turning it into a list of envelopes here perhaps.
1181	*/
1182
1183	WorkQ = NULL;
1184	for (i = wc; --i >= 0; )
1185	{
1186		w = (WORK *) xalloc(sizeof *w);
1187		w->w_name = WorkList[i].w_name;
1188		w->w_host = WorkList[i].w_host;
1189		w->w_lock = WorkList[i].w_lock;
1190		w->w_tooyoung = WorkList[i].w_tooyoung;
1191		w->w_pri = WorkList[i].w_pri;
1192		w->w_ctime = WorkList[i].w_ctime;
1193		w->w_next = WorkQ;
1194		WorkQ = w;
1195	}
1196	if (WorkList != NULL)
1197		free(WorkList);
1198	WorkList = NULL;
1199	WorkListSize = 0;
1200
1201	if (tTd(40, 1))
1202	{
1203		for (w = WorkQ; w != NULL; w = w->w_next)
1204			printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
1205	}
1206
1207	return (wn);
1208}
1209/*
1210**  GROW_WLIST -- make the work list larger
1211**
1212**	Parameters:
1213**		none.
1214**
1215**	Returns:
1216**		none.
1217**
1218**	Side Effects:
1219**		Adds another QUEUESEGSIZE entries to WorkList if possible.
1220**		It can fail if there isn't enough memory, so WorkListSize
1221**		should be checked again upon return.
1222*/
1223
1224void
1225grow_wlist()
1226{
1227	if (tTd(41, 1))
1228		printf("grow_wlist: WorkListSize=%d\n", WorkListSize);
1229	if (WorkList == NULL)
1230	{
1231		WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1));
1232		WorkListSize = QUEUESEGSIZE;
1233	}
1234	else
1235	{
1236		int newsize = WorkListSize + QUEUESEGSIZE;
1237		WORK *newlist = (WORK *) realloc((char *)WorkList,
1238					  (unsigned)sizeof(WORK) * (newsize + 1));
1239
1240		if (newlist != NULL)
1241		{
1242			WorkListSize = newsize;
1243			WorkList = newlist;
1244			if (LogLevel > 1)
1245			{
1246				sm_syslog(LOG_NOTICE, NOQID,
1247					"grew WorkList for %s to %d",
1248					QueueDir, WorkListSize);
1249			}
1250		}
1251		else if (LogLevel > 0)
1252		{
1253			sm_syslog(LOG_ALERT, NOQID,
1254				"FAILED to grow WorkList for %s to %d",
1255				QueueDir, newsize);
1256		}
1257	}
1258	if (tTd(41, 1))
1259		printf("grow_wlist: WorkListSize now %d\n", WorkListSize);
1260}
1261/*
1262**  WORKCMPF0 -- simple priority-only compare function.
1263**
1264**	Parameters:
1265**		a -- the first argument.
1266**		b -- the second argument.
1267**
1268**	Returns:
1269**		-1 if a < b
1270**		 0 if a == b
1271**		+1 if a > b
1272**
1273**	Side Effects:
1274**		none.
1275*/
1276
1277int
1278workcmpf0(a, b)
1279	register WORK *a;
1280	register WORK *b;
1281{
1282	long pa = a->w_pri;
1283	long pb = b->w_pri;
1284
1285	if (pa == pb)
1286		return 0;
1287	else if (pa > pb)
1288		return 1;
1289	else
1290		return -1;
1291}
1292/*
1293**  WORKCMPF1 -- first compare function for ordering work based on host name.
1294**
1295**	Sorts on host name, lock status, and priority in that order.
1296**
1297**	Parameters:
1298**		a -- the first argument.
1299**		b -- the second argument.
1300**
1301**	Returns:
1302**		<0 if a < b
1303**		 0 if a == b
1304**		>0 if a > b
1305**
1306**	Side Effects:
1307**		none.
1308*/
1309
1310int
1311workcmpf1(a, b)
1312	register WORK *a;
1313	register WORK *b;
1314{
1315	int i;
1316	extern int sm_strcasecmp __P((char *, char *));
1317
1318	/* host name */
1319	if (a->w_host != NULL && b->w_host == NULL)
1320		return 1;
1321	else if (a->w_host == NULL && b->w_host != NULL)
1322		return -1;
1323	if (a->w_host != NULL && b->w_host != NULL &&
1324	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1325		return i;
1326
1327	/* lock status */
1328	if (a->w_lock != b->w_lock)
1329		return b->w_lock - a->w_lock;
1330
1331	/* job priority */
1332	return a->w_pri - b->w_pri;
1333}
1334/*
1335**  WORKCMPF2 -- second compare function for ordering work based on host name.
1336**
1337**	Sorts on lock status, host name, and priority in that order.
1338**
1339**	Parameters:
1340**		a -- the first argument.
1341**		b -- the second argument.
1342**
1343**	Returns:
1344**		<0 if a < b
1345**		 0 if a == b
1346**		>0 if a > b
1347**
1348**	Side Effects:
1349**		none.
1350*/
1351
1352int
1353workcmpf2(a, b)
1354	register WORK *a;
1355	register WORK *b;
1356{
1357	int i;
1358	extern int sm_strcasecmp __P((char *, char *));
1359
1360	/* lock status */
1361	if (a->w_lock != b->w_lock)
1362		return a->w_lock - b->w_lock;
1363
1364	/* host name */
1365	if (a->w_host != NULL && b->w_host == NULL)
1366		return 1;
1367	else if (a->w_host == NULL && b->w_host != NULL)
1368		return -1;
1369	if (a->w_host != NULL && b->w_host != NULL &&
1370	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1371		return i;
1372
1373	/* job priority */
1374	return a->w_pri - b->w_pri;
1375}
1376/*
1377**  WORKCMPF3 -- simple submission-time-only compare function.
1378**
1379**	Parameters:
1380**		a -- the first argument.
1381**		b -- the second argument.
1382**
1383**	Returns:
1384**		-1 if a < b
1385**		 0 if a == b
1386**		+1 if a > b
1387**
1388**	Side Effects:
1389**		none.
1390*/
1391
1392int
1393workcmpf3(a, b)
1394	register WORK *a;
1395	register WORK *b;
1396{
1397	if (a->w_ctime > b->w_ctime)
1398		return 1;
1399	else if (a->w_ctime < b->w_ctime)
1400		return -1;
1401	else
1402		return 0;
1403}
1404/*
1405**  DOWORK -- do a work request.
1406**
1407**	Parameters:
1408**		id -- the ID of the job to run.
1409**		forkflag -- if set, run this in background.
1410**		requeueflag -- if set, reinstantiate the queue quickly.
1411**			This is used when expanding aliases in the queue.
1412**			If forkflag is also set, it doesn't wait for the
1413**			child.
1414**		e - the envelope in which to run it.
1415**
1416**	Returns:
1417**		process id of process that is running the queue job.
1418**
1419**	Side Effects:
1420**		The work request is satisfied if possible.
1421*/
1422
1423pid_t
1424dowork(id, forkflag, requeueflag, e)
1425	char *id;
1426	bool forkflag;
1427	bool requeueflag;
1428	register ENVELOPE *e;
1429{
1430	register pid_t pid;
1431	extern bool readqf __P((ENVELOPE *));
1432
1433	if (tTd(40, 1))
1434		printf("dowork(%s)\n", id);
1435
1436	/*
1437	**  Fork for work.
1438	*/
1439
1440	if (forkflag)
1441	{
1442		pid = fork();
1443		if (pid < 0)
1444		{
1445			syserr("dowork: cannot fork");
1446			return 0;
1447		}
1448		else if (pid > 0)
1449		{
1450			/* parent -- clean out connection cache */
1451			mci_flush(FALSE, NULL);
1452		}
1453		else
1454		{
1455			/* child -- error messages to the transcript */
1456			QuickAbort = OnlyOneError = FALSE;
1457
1458			/*
1459			**  Since the delivery may happen in a child and the
1460			**  parent does not wait, the parent may close the
1461			**  maps thereby removing any shared memory used by
1462			**  the map.  Therefore, open a copy of the maps for
1463			**  the delivery process.
1464			*/
1465
1466			initmaps(FALSE, e);
1467		}
1468	}
1469	else
1470	{
1471		pid = 0;
1472	}
1473
1474	if (pid == 0)
1475	{
1476		/*
1477		**  CHILD
1478		**	Lock the control file to avoid duplicate deliveries.
1479		**		Then run the file as though we had just read it.
1480		**	We save an idea of the temporary name so we
1481		**		can recover on interrupt.
1482		*/
1483
1484		/* set basic modes, etc. */
1485		(void) alarm(0);
1486		clearenvelope(e, FALSE);
1487		e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
1488		e->e_sendmode = SM_DELIVER;
1489		e->e_errormode = EM_MAIL;
1490		e->e_id = id;
1491		GrabTo = UseErrorsTo = FALSE;
1492		ExitStat = EX_OK;
1493		if (forkflag)
1494		{
1495			disconnect(1, e);
1496			OpMode = MD_DELIVER;
1497		}
1498		sm_setproctitle(TRUE, "%s: from queue", id);
1499		if (LogLevel > 76)
1500			sm_syslog(LOG_DEBUG, e->e_id,
1501				"dowork, pid=%d",
1502				getpid());
1503
1504		/* don't use the headers from sendmail.cf... */
1505		e->e_header = NULL;
1506
1507		/* read the queue control file -- return if locked */
1508		if (!readqf(e))
1509		{
1510			if (tTd(40, 4) && e->e_id != NULL)
1511				printf("readqf(%s) failed\n", e->e_id);
1512			e->e_id = NULL;
1513			if (forkflag)
1514				finis(FALSE, EX_OK);
1515			else
1516				return 0;
1517		}
1518
1519		e->e_flags |= EF_INQUEUE;
1520		eatheader(e, requeueflag);
1521
1522		if (requeueflag)
1523			queueup(e, FALSE);
1524
1525		/* do the delivery */
1526		sendall(e, SM_DELIVER);
1527
1528		/* finish up and exit */
1529		if (forkflag)
1530			finis(TRUE, ExitStat);
1531		else
1532			dropenvelope(e, TRUE);
1533	}
1534	e->e_id = NULL;
1535	return pid;
1536}
1537/*
1538**  READQF -- read queue file and set up environment.
1539**
1540**	Parameters:
1541**		e -- the envelope of the job to run.
1542**
1543**	Returns:
1544**		TRUE if it successfully read the queue file.
1545**		FALSE otherwise.
1546**
1547**	Side Effects:
1548**		The queue file is returned locked.
1549*/
1550
1551bool
1552readqf(e)
1553	register ENVELOPE *e;
1554{
1555	register FILE *qfp;
1556	ADDRESS *ctladdr;
1557	struct stat st;
1558	char *bp;
1559	int qfver = 0;
1560	long hdrsize = 0;
1561	register char *p;
1562	char *orcpt = NULL;
1563	bool nomore = FALSE;
1564	char qf[MAXQFNAME];
1565	char buf[MAXLINE];
1566	extern ADDRESS *setctluser __P((char *, int));
1567
1568	/*
1569	**  Read and process the file.
1570	*/
1571
1572	strcpy(qf, queuename(e, 'q'));
1573	qfp = fopen(qf, "r+");
1574	if (qfp == NULL)
1575	{
1576		if (tTd(40, 8))
1577			printf("readqf(%s): fopen failure (%s)\n",
1578				qf, errstring(errno));
1579		if (errno != ENOENT)
1580			syserr("readqf: no control file %s", qf);
1581		return FALSE;
1582	}
1583
1584	if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
1585	{
1586		/* being processed by another queuer */
1587		if (Verbose || tTd(40, 8))
1588			printf("%s: locked\n", e->e_id);
1589		if (LogLevel > 19)
1590			sm_syslog(LOG_DEBUG, e->e_id, "locked");
1591		(void) fclose(qfp);
1592		return FALSE;
1593	}
1594
1595	/*
1596	**  Check the queue file for plausibility to avoid attacks.
1597	*/
1598
1599	if (fstat(fileno(qfp), &st) < 0)
1600	{
1601		/* must have been being processed by someone else */
1602		if (tTd(40, 8))
1603			printf("readqf(%s): fstat failure (%s)\n",
1604				qf, errstring(errno));
1605		fclose(qfp);
1606		return FALSE;
1607	}
1608
1609	if ((st.st_uid != geteuid() && geteuid() != RealUid) ||
1610	    bitset(S_IWOTH|S_IWGRP, st.st_mode))
1611	{
1612		if (LogLevel > 0)
1613		{
1614			sm_syslog(LOG_ALERT, e->e_id,
1615				"bogus queue file, uid=%d, mode=%o",
1616				st.st_uid, st.st_mode);
1617		}
1618		if (tTd(40, 8))
1619			printf("readqf(%s): bogus file\n", qf);
1620		loseqfile(e, "bogus file uid in mqueue");
1621		fclose(qfp);
1622		return FALSE;
1623	}
1624
1625	if (st.st_size == 0)
1626	{
1627		/* must be a bogus file -- if also old, just remove it */
1628		if (st.st_ctime + 10 * 60 < curtime())
1629		{
1630			qf[0] = 'd';
1631			(void) unlink(qf);
1632			qf[0] = 'q';
1633			(void) unlink(qf);
1634		}
1635		fclose(qfp);
1636		return FALSE;
1637	}
1638
1639	if (st.st_nlink == 0)
1640	{
1641		/*
1642		**  Race condition -- we got a file just as it was being
1643		**  unlinked.  Just assume it is zero length.
1644		*/
1645
1646		fclose(qfp);
1647		return FALSE;
1648	}
1649
1650	/* good file -- save this lock */
1651	e->e_lockfp = qfp;
1652
1653	/* do basic system initialization */
1654	initsys(e);
1655	define('i', e->e_id, e);
1656
1657	LineNumber = 0;
1658	e->e_flags |= EF_GLOBALERRS;
1659	OpMode = MD_DELIVER;
1660	ctladdr = NULL;
1661	e->e_dfino = -1;
1662	e->e_msgsize = -1;
1663	while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
1664	{
1665		register char *p;
1666		u_long qflags;
1667		ADDRESS *q;
1668		int mid;
1669		auto char *ep;
1670
1671		if (tTd(40, 4))
1672			printf("+++++ %s\n", bp);
1673		if (nomore)
1674		{
1675			/* hack attack */
1676			syserr("SECURITY ALERT: extra data in qf: %s", bp);
1677			fclose(qfp);
1678			loseqfile(e, "bogus queue line");
1679			return FALSE;
1680		}
1681		switch (bp[0])
1682		{
1683		  case 'V':		/* queue file version number */
1684			qfver = atoi(&bp[1]);
1685			if (qfver <= QF_VERSION)
1686				break;
1687			syserr("Version number in qf (%d) greater than max (%d)",
1688				qfver, QF_VERSION);
1689			fclose(qfp);
1690			loseqfile(e, "unsupported qf file version");
1691			return FALSE;
1692
1693		  case 'C':		/* specify controlling user */
1694			ctladdr = setctluser(&bp[1], qfver);
1695			break;
1696
1697		  case 'Q':		/* original recipient */
1698			orcpt = newstr(&bp[1]);
1699			break;
1700
1701		  case 'R':		/* specify recipient */
1702			p = bp;
1703			qflags = 0;
1704			if (qfver >= 1)
1705			{
1706				/* get flag bits */
1707				while (*++p != '\0' && *p != ':')
1708				{
1709					switch (*p)
1710					{
1711					  case 'N':
1712						qflags |= QHASNOTIFY;
1713						break;
1714
1715					  case 'S':
1716						qflags |= QPINGONSUCCESS;
1717						break;
1718
1719					  case 'F':
1720						qflags |= QPINGONFAILURE;
1721						break;
1722
1723					  case 'D':
1724						qflags |= QPINGONDELAY;
1725						break;
1726
1727					  case 'P':
1728						qflags |= QPRIMARY;
1729						break;
1730					}
1731				}
1732			}
1733			else
1734				qflags |= QPRIMARY;
1735			q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
1736			if (q != NULL)
1737			{
1738				q->q_alias = ctladdr;
1739				if (qfver >= 1)
1740					q->q_flags &= ~Q_PINGFLAGS;
1741				q->q_flags |= qflags;
1742				q->q_orcpt = orcpt;
1743				(void) recipient(q, &e->e_sendqueue, 0, e);
1744			}
1745			orcpt = NULL;
1746			break;
1747
1748		  case 'E':		/* specify error recipient */
1749			/* no longer used */
1750			break;
1751
1752		  case 'H':		/* header */
1753			(void) chompheader(&bp[1], FALSE, NULL, e);
1754			hdrsize += strlen(&bp[1]);
1755			break;
1756
1757		  case 'L':		/* Solaris Content-Length: */
1758		  case 'M':		/* message */
1759			/* ignore this; we want a new message next time */
1760			break;
1761
1762		  case 'S':		/* sender */
1763			setsender(newstr(&bp[1]), e, NULL, '\0', TRUE);
1764			break;
1765
1766		  case 'B':		/* body type */
1767			e->e_bodytype = newstr(&bp[1]);
1768			break;
1769
1770#if _FFR_SAVE_CHARSET
1771		  case 'X':		/* character set */
1772			e->e_charset = newstr(&bp[1]);
1773			break;
1774#endif
1775
1776		  case 'D':		/* data file name */
1777			/* obsolete -- ignore */
1778			break;
1779
1780		  case 'T':		/* init time */
1781			e->e_ctime = atol(&bp[1]);
1782			break;
1783
1784		  case 'I':		/* data file's inode number */
1785			/* regenerated below */
1786			break;
1787
1788		  case 'K':		/* time of last deliver attempt */
1789			e->e_dtime = atol(&buf[1]);
1790			break;
1791
1792		  case 'N':		/* number of delivery attempts */
1793			e->e_ntries = atoi(&buf[1]);
1794
1795			/* if this has been tried recently, let it be */
1796			if (e->e_ntries > 0 &&
1797			    MinQueueAge > 0 && e->e_dtime <= curtime() &&
1798			    curtime() < e->e_dtime + MinQueueAge)
1799			{
1800				char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
1801
1802				if (Verbose || tTd(40, 8))
1803					printf("%s: too young (%s)\n",
1804						e->e_id, howlong);
1805				if (LogLevel > 19)
1806					sm_syslog(LOG_DEBUG, e->e_id,
1807						"too young (%s)",
1808						howlong);
1809				e->e_id = NULL;
1810				unlockqueue(e);
1811				return FALSE;
1812			}
1813			break;
1814
1815		  case 'P':		/* message priority */
1816			e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
1817			break;
1818
1819		  case 'F':		/* flag bits */
1820			if (strncmp(bp, "From ", 5) == 0)
1821			{
1822				/* we are being spoofed! */
1823				syserr("SECURITY ALERT: bogus qf line %s", bp);
1824				fclose(qfp);
1825				loseqfile(e, "bogus queue line");
1826				return FALSE;
1827			}
1828			for (p = &bp[1]; *p != '\0'; p++)
1829			{
1830				switch (*p)
1831				{
1832				  case 'w':	/* warning sent */
1833					e->e_flags |= EF_WARNING;
1834					break;
1835
1836				  case 'r':	/* response */
1837					e->e_flags |= EF_RESPONSE;
1838					break;
1839
1840				  case '8':	/* has 8 bit data */
1841					e->e_flags |= EF_HAS8BIT;
1842					break;
1843
1844				  case 'b':	/* delete Bcc: header */
1845					e->e_flags |= EF_DELETE_BCC;
1846					break;
1847
1848				  case 'd':	/* envelope has DSN RET= */
1849					e->e_flags |= EF_RET_PARAM;
1850					break;
1851
1852				  case 'n':	/* don't return body */
1853					e->e_flags |= EF_NO_BODY_RETN;
1854					break;
1855				}
1856			}
1857			break;
1858
1859		  case 'Z':		/* original envelope id from ESMTP */
1860			e->e_envid = newstr(&bp[1]);
1861			break;
1862
1863		  case '$':		/* define macro */
1864			mid = macid(&bp[1], &ep);
1865			define(mid, newstr(ep), e);
1866			break;
1867
1868		  case '.':		/* terminate file */
1869			nomore = TRUE;
1870			break;
1871
1872		  default:
1873			syserr("readqf: %s: line %d: bad line \"%s\"",
1874				qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
1875			fclose(qfp);
1876			loseqfile(e, "unrecognized line");
1877			return FALSE;
1878		}
1879
1880		if (bp != buf)
1881			free(bp);
1882	}
1883
1884	/*
1885	**  If we haven't read any lines, this queue file is empty.
1886	**  Arrange to remove it without referencing any null pointers.
1887	*/
1888
1889	if (LineNumber == 0)
1890	{
1891		errno = 0;
1892		e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
1893		return TRUE;
1894	}
1895
1896	/*
1897	**  Arrange to read the data file.
1898	*/
1899
1900	p = queuename(e, 'd');
1901	e->e_dfp = fopen(p, "r");
1902	if (e->e_dfp == NULL)
1903	{
1904		syserr("readqf: cannot open %s", p);
1905	}
1906	else
1907	{
1908		e->e_flags |= EF_HAS_DF;
1909		if (fstat(fileno(e->e_dfp), &st) >= 0)
1910		{
1911			e->e_msgsize = st.st_size + hdrsize;
1912			e->e_dfdev = st.st_dev;
1913			e->e_dfino = st.st_ino;
1914		}
1915	}
1916
1917	return TRUE;
1918}
1919/*
1920**  PRINTQUEUE -- print out a representation of the mail queue
1921**
1922**	Parameters:
1923**		none.
1924**
1925**	Returns:
1926**		none.
1927**
1928**	Side Effects:
1929**		Prints a listing of the mail queue on the standard output.
1930*/
1931
1932void
1933printqueue()
1934{
1935	register WORK *w;
1936	FILE *f;
1937	int nrequests;
1938	char buf[MAXLINE];
1939
1940	/*
1941	**  Check for permission to print the queue
1942	*/
1943
1944	if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
1945	{
1946		struct stat st;
1947# ifdef NGROUPS_MAX
1948		int n;
1949		extern GIDSET_T InitialGidSet[NGROUPS_MAX];
1950# endif
1951
1952		if (stat(QueueDir, &st) < 0)
1953		{
1954			syserr("Cannot stat %s", QueueDir);
1955			return;
1956		}
1957# ifdef NGROUPS_MAX
1958		n = NGROUPS_MAX;
1959		while (--n >= 0)
1960		{
1961			if (InitialGidSet[n] == st.st_gid)
1962				break;
1963		}
1964		if (n < 0 && RealGid != st.st_gid)
1965# else
1966		if (RealGid != st.st_gid)
1967# endif
1968		{
1969			usrerr("510 You are not permitted to see the queue");
1970			setstat(EX_NOPERM);
1971			return;
1972		}
1973	}
1974
1975	/*
1976	**  Read and order the queue.
1977	*/
1978
1979	nrequests = orderq(TRUE);
1980
1981	/*
1982	**  Print the work list that we have read.
1983	*/
1984
1985	/* first see if there is anything */
1986	if (nrequests <= 0)
1987	{
1988		printf("Mail queue is empty\n");
1989		return;
1990	}
1991
1992	CurrentLA = getla();	/* get load average */
1993
1994	printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
1995	if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
1996		printf(", only %d printed", MaxQueueRun);
1997	if (Verbose)
1998		printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
1999	else
2000		printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
2001	for (w = WorkQ; w != NULL; w = w->w_next)
2002	{
2003		struct stat st;
2004		auto time_t submittime = 0;
2005		long dfsize;
2006		int flags = 0;
2007		int qfver;
2008		char statmsg[MAXLINE];
2009		char bodytype[MAXNAME + 1];
2010
2011		printf("%8s", w->w_name + 2);
2012		f = fopen(w->w_name, "r");
2013		if (f == NULL)
2014		{
2015			printf(" (job completed)\n");
2016			errno = 0;
2017			continue;
2018		}
2019		w->w_name[0] = 'd';
2020		if (stat(w->w_name, &st) >= 0)
2021			dfsize = st.st_size;
2022		else
2023			dfsize = -1;
2024		if (w->w_lock)
2025			printf("*");
2026		else if (w->w_tooyoung)
2027			printf("-");
2028		else if (shouldqueue(w->w_pri, w->w_ctime))
2029			printf("X");
2030		else
2031			printf(" ");
2032		errno = 0;
2033
2034		statmsg[0] = bodytype[0] = '\0';
2035		qfver = 0;
2036		while (fgets(buf, sizeof buf, f) != NULL)
2037		{
2038			register int i;
2039			register char *p;
2040
2041			fixcrlf(buf, TRUE);
2042			switch (buf[0])
2043			{
2044			  case 'V':	/* queue file version */
2045				qfver = atoi(&buf[1]);
2046				break;
2047
2048			  case 'M':	/* error message */
2049				if ((i = strlen(&buf[1])) >= sizeof statmsg)
2050					i = sizeof statmsg - 1;
2051				bcopy(&buf[1], statmsg, i);
2052				statmsg[i] = '\0';
2053				break;
2054
2055			  case 'B':	/* body type */
2056				if ((i = strlen(&buf[1])) >= sizeof bodytype)
2057					i = sizeof bodytype - 1;
2058				bcopy(&buf[1], bodytype, i);
2059				bodytype[i] = '\0';
2060				break;
2061
2062			  case 'S':	/* sender name */
2063				if (Verbose)
2064					printf("%8ld %10ld%c%.12s %.78s",
2065					    dfsize,
2066					    w->w_pri,
2067					    bitset(EF_WARNING, flags) ? '+' : ' ',
2068					    ctime(&submittime) + 4,
2069					    &buf[1]);
2070				else
2071					printf("%8ld %.16s %.45s", dfsize,
2072					    ctime(&submittime), &buf[1]);
2073				if (statmsg[0] != '\0' || bodytype[0] != '\0')
2074				{
2075					printf("\n    %10.10s", bodytype);
2076					if (statmsg[0] != '\0')
2077						printf("   (%.*s)",
2078							Verbose ? 100 : 60,
2079							statmsg);
2080				}
2081				break;
2082
2083			  case 'C':	/* controlling user */
2084				if (Verbose)
2085					printf("\n\t\t\t\t      (---%.74s---)",
2086						&buf[1]);
2087				break;
2088
2089			  case 'R':	/* recipient name */
2090				p = &buf[1];
2091				if (qfver >= 1)
2092				{
2093					p = strchr(p, ':');
2094					if (p == NULL)
2095						break;
2096					p++;
2097				}
2098				if (Verbose)
2099					printf("\n\t\t\t\t\t  %.78s", p);
2100				else
2101					printf("\n\t\t\t\t   %.45s", p);
2102				break;
2103
2104			  case 'T':	/* creation time */
2105				submittime = atol(&buf[1]);
2106				break;
2107
2108			  case 'F':	/* flag bits */
2109				for (p = &buf[1]; *p != '\0'; p++)
2110				{
2111					switch (*p)
2112					{
2113					  case 'w':
2114						flags |= EF_WARNING;
2115						break;
2116					}
2117				}
2118			}
2119		}
2120		if (submittime == (time_t) 0)
2121			printf(" (no control file)");
2122		printf("\n");
2123		(void) fclose(f);
2124	}
2125}
2126
2127# endif /* QUEUE */
2128/*
2129**  QUEUENAME -- build a file name in the queue directory for this envelope.
2130**
2131**	Assigns an id code if one does not already exist.
2132**	This code is very careful to avoid trashing existing files
2133**	under any circumstances.
2134**
2135**	Parameters:
2136**		e -- envelope to build it in/from.
2137**		type -- the file type, used as the first character
2138**			of the file name.
2139**
2140**	Returns:
2141**		a pointer to the new file name (in a static buffer).
2142**
2143**	Side Effects:
2144**		If no id code is already assigned, queuename will
2145**		assign an id code, create a qf file, and leave a
2146**		locked, open-for-write file pointer in the envelope.
2147*/
2148
2149#ifndef ENOLCK
2150# define ENOLCK		-1
2151#endif
2152#ifndef ENOSPC
2153# define ENOSPC		-1
2154#endif
2155
2156char *
2157queuename(e, type)
2158	register ENVELOPE *e;
2159	int type;
2160{
2161	static pid_t pid = -1;
2162	static char c0;
2163	static char c1;
2164	static char c2;
2165	time_t now;
2166	struct tm *tm;
2167	static char buf[MAXNAME + 1];
2168
2169	if (e->e_id == NULL)
2170	{
2171		char qf[MAXQFNAME];
2172
2173		/* find a unique id */
2174		if (pid != getpid())
2175		{
2176			/* new process -- start back at "AA" */
2177			pid = getpid();
2178			now = curtime();
2179			tm = localtime(&now);
2180			c0 = 'A' + tm->tm_hour;
2181			c1 = 'A';
2182			c2 = 'A' - 1;
2183		}
2184		(void) snprintf(qf, sizeof qf, "qf%cAA%05d", c0, pid);
2185
2186		while (c1 < '~' || c2 < 'Z')
2187		{
2188			int i;
2189			int attempts = 0;
2190
2191			if (c2 >= 'Z')
2192			{
2193				c1++;
2194				c2 = 'A' - 1;
2195			}
2196			qf[3] = c1;
2197			qf[4] = ++c2;
2198			if (tTd(7, 20))
2199				printf("queuename: trying \"%s\"\n", qf);
2200
2201			i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
2202			if (i < 0)
2203			{
2204				if (errno == EEXIST)
2205					continue;
2206				syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
2207					qf, QueueDir, geteuid());
2208				finis(FALSE, EX_UNAVAILABLE);
2209			}
2210			do
2211			{
2212				if (attempts > 0)
2213					sleep(attempts);
2214				e->e_lockfp = 0;
2215				if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
2216				{
2217					e->e_lockfp = fdopen(i, "w");
2218					break;
2219				}
2220			} while ((errno == ENOLCK || errno == ENOSPC) &&
2221				 attempts++ < 4);
2222
2223			/* Successful lock */
2224			if (e->e_lockfp != 0)
2225				break;
2226
2227#if !HASFLOCK
2228			if (errno != EAGAIN && errno != EACCES)
2229#else
2230			if (errno != EWOULDBLOCK)
2231#endif
2232			{
2233				syserr("queuename: Cannot lock \"%s\" in \"%s\" (euid=%d)",
2234					qf, QueueDir, geteuid());
2235				finis(FALSE, EX_OSERR);
2236			}
2237
2238			/* a reader got the file; abandon it and try again */
2239			(void) close(i);
2240		}
2241		if (c1 >= '~' && c2 >= 'Z')
2242		{
2243			syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
2244				qf, QueueDir, geteuid());
2245			finis(FALSE, EX_OSERR);
2246		}
2247		e->e_id = newstr(&qf[2]);
2248		define('i', e->e_id, e);
2249		if (tTd(7, 1))
2250			printf("queuename: assigned id %s, env=%lx\n",
2251			       e->e_id, (u_long) e);
2252		if (tTd(7, 9))
2253		{
2254			printf("  lockfd=");
2255			dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
2256		}
2257		if (LogLevel > 93)
2258			sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
2259	}
2260
2261	if (type == '\0')
2262		return (NULL);
2263	(void) snprintf(buf, sizeof buf, "%cf%s", type, e->e_id);
2264	if (tTd(7, 2))
2265		printf("queuename: %s\n", buf);
2266	return (buf);
2267}
2268/*
2269**  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
2270**
2271**	Parameters:
2272**		e -- the envelope to unlock.
2273**
2274**	Returns:
2275**		none
2276**
2277**	Side Effects:
2278**		unlocks the queue for `e'.
2279*/
2280
2281void
2282unlockqueue(e)
2283	ENVELOPE *e;
2284{
2285	if (tTd(51, 4))
2286		printf("unlockqueue(%s)\n",
2287			e->e_id == NULL ? "NOQUEUE" : e->e_id);
2288
2289	/* if there is a lock file in the envelope, close it */
2290	if (e->e_lockfp != NULL)
2291		xfclose(e->e_lockfp, "unlockqueue", e->e_id);
2292	e->e_lockfp = NULL;
2293
2294	/* don't create a queue id if we don't already have one */
2295	if (e->e_id == NULL)
2296		return;
2297
2298	/* remove the transcript */
2299	if (LogLevel > 87)
2300		sm_syslog(LOG_DEBUG, e->e_id, "unlock");
2301	if (!tTd(51, 104))
2302		xunlink(queuename(e, 'x'));
2303
2304}
2305/*
2306**  SETCTLUSER -- create a controlling address
2307**
2308**	Create a fake "address" given only a local login name; this is
2309**	used as a "controlling user" for future recipient addresses.
2310**
2311**	Parameters:
2312**		user -- the user name of the controlling user.
2313**		qfver -- the version stamp of this qf file.
2314**
2315**	Returns:
2316**		An address descriptor for the controlling user.
2317**
2318**	Side Effects:
2319**		none.
2320*/
2321
2322ADDRESS *
2323setctluser(user, qfver)
2324	char *user;
2325	int qfver;
2326{
2327	register ADDRESS *a;
2328	struct passwd *pw;
2329	char *p;
2330
2331	/*
2332	**  See if this clears our concept of controlling user.
2333	*/
2334
2335	if (user == NULL || *user == '\0')
2336		return NULL;
2337
2338	/*
2339	**  Set up addr fields for controlling user.
2340	*/
2341
2342	a = (ADDRESS *) xalloc(sizeof *a);
2343	bzero((char *) a, sizeof *a);
2344
2345	if (*user == '\0')
2346	{
2347		p = NULL;
2348		a->q_user = newstr(DefUser);
2349	}
2350	else if (*user == ':')
2351	{
2352		p = &user[1];
2353		a->q_user = newstr(p);
2354	}
2355	else
2356	{
2357		p = strtok(user, ":");
2358		a->q_user = newstr(user);
2359		if (qfver >= 2)
2360		{
2361			if ((p = strtok(NULL, ":")) != NULL)
2362				a->q_uid = atoi(p);
2363			if ((p = strtok(NULL, ":")) != NULL)
2364				a->q_gid = atoi(p);
2365			if ((p = strtok(NULL, ":")) != NULL)
2366				a->q_flags |= QGOODUID;
2367		}
2368		else if ((pw = sm_getpwnam(user)) != NULL)
2369		{
2370			if (strcmp(pw->pw_dir, "/") == 0)
2371				a->q_home = "";
2372			else
2373				a->q_home = newstr(pw->pw_dir);
2374			a->q_uid = pw->pw_uid;
2375			a->q_gid = pw->pw_gid;
2376			a->q_flags |= QGOODUID;
2377		}
2378	}
2379
2380	a->q_flags |= QPRIMARY;		/* flag as a "ctladdr"  */
2381	a->q_mailer = LocalMailer;
2382	if (p == NULL)
2383		a->q_paddr = a->q_user;
2384	else
2385		a->q_paddr = newstr(p);
2386	return a;
2387}
2388/*
2389**  LOSEQFILE -- save the qf as Qf and try to let someone know
2390**
2391**	Parameters:
2392**		e -- the envelope (e->e_id will be used).
2393**		why -- reported to whomever can hear.
2394**
2395**	Returns:
2396**		none.
2397*/
2398
2399void
2400loseqfile(e, why)
2401	register ENVELOPE *e;
2402	char *why;
2403{
2404	char *p;
2405	char buf[MAXQFNAME + 1];
2406
2407	if (e == NULL || e->e_id == NULL)
2408		return;
2409	p = queuename(e, 'q');
2410	if (strlen(p) > MAXQFNAME)
2411	{
2412		syserr("loseqfile: queuename (%s) too long", p);
2413		return;
2414	}
2415	strcpy(buf, p);
2416	p = queuename(e, 'Q');
2417	if (rename(buf, p) < 0)
2418		syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
2419	else if (LogLevel > 0)
2420		sm_syslog(LOG_ALERT, e->e_id,
2421			"Losing %s: %s", buf, why);
2422}
2423