xref: /csrg-svn/usr.sbin/sendmail/src/conf.c (revision 60160)
122698Sdist /*
234920Sbostic  * Copyright (c) 1983 Eric P. Allman
333728Sbostic  * Copyright (c) 1988 Regents of the University of California.
433728Sbostic  * All rights reserved.
533728Sbostic  *
642825Sbostic  * %sccs.include.redist.c%
733728Sbostic  */
822698Sdist 
922698Sdist #ifndef lint
10*60160Seric static char sccsid[] = "@(#)conf.c	6.58 (Berkeley) 05/20/93";
1133728Sbostic #endif /* not lint */
1222698Sdist 
1314881Seric # include <sys/ioctl.h>
1458082Seric # include <sys/param.h>
1558153Seric # include <signal.h>
1636928Sbostic # include <pwd.h>
173309Seric # include "sendmail.h"
1840980Sbostic # include "pathnames.h"
19404Seric 
20294Seric /*
213309Seric **  CONF.C -- Sendmail Configuration Tables.
22294Seric **
23294Seric **	Defines the configuration of this installation.
24294Seric **
251388Seric **	Configuration Variables:
262897Seric **		HdrInfo -- a table describing well-known header fields.
272897Seric **			Each entry has the field name and some flags,
284147Seric **			which are described in sendmail.h.
294093Seric **
304093Seric **	Notes:
314093Seric **		I have tried to put almost all the reasonable
324093Seric **		configuration information into the configuration
334093Seric **		file read at runtime.  My intent is that anything
344093Seric **		here is a function of the version of UNIX you
354093Seric **		are running, or is really static -- for example
364093Seric **		the headers are a superset of widely used
374093Seric **		protocols.  If you find yourself playing with
384093Seric **		this file too much, you may be making a mistake!
39294Seric */
40294Seric 
41294Seric 
42294Seric 
43294Seric 
444437Seric /*
452897Seric **  Header info table
463057Seric **	Final (null) entry contains the flags used for any other field.
474147Seric **
484147Seric **	Not all of these are actually handled specially by sendmail
494147Seric **	at this time.  They are included as placeholders, to let
504147Seric **	you know that "someday" I intend to have sendmail do
514147Seric **	something with them.
522897Seric */
532897Seric 
542897Seric struct hdrinfo	HdrInfo[] =
552897Seric {
568060Seric 		/* originator fields, most to least significant  */
5711417Seric 	"resent-sender",	H_FROM|H_RESENT,
5811417Seric 	"resent-from",		H_FROM|H_RESENT,
5925686Seric 	"resent-reply-to",	H_FROM|H_RESENT,
609055Seric 	"sender",		H_FROM,
619055Seric 	"from",			H_FROM,
6225686Seric 	"reply-to",		H_FROM,
639055Seric 	"full-name",		H_ACHECK,
6457359Seric 	"return-receipt-to",	H_FROM /* |H_RECEIPTTO */,
6557359Seric 	"errors-to",		H_FROM|H_ERRORSTO,
6658796Seric 
678060Seric 		/* destination fields */
689055Seric 	"to",			H_RCPT,
6911417Seric 	"resent-to",		H_RCPT|H_RESENT,
709055Seric 	"cc",			H_RCPT,
7111417Seric 	"resent-cc",		H_RCPT|H_RESENT,
729055Seric 	"bcc",			H_RCPT|H_ACHECK,
7311417Seric 	"resent-bcc",		H_RCPT|H_ACHECK|H_RESENT,
7456215Seric 	"apparently-to",	H_RCPT,
7558796Seric 
768060Seric 		/* message identification and control */
7711417Seric 	"message-id",		0,
7811417Seric 	"resent-message-id",	H_RESENT,
799055Seric 	"message",		H_EOH,
809055Seric 	"text",			H_EOH,
8158796Seric 
8211417Seric 		/* date fields */
8311417Seric 	"date",			0,
8411417Seric 	"resent-date",		H_RESENT,
8558796Seric 
868060Seric 		/* trace fields */
879055Seric 	"received",		H_TRACE|H_FORCE,
8859318Seric 	"x400-received",	H_TRACE|H_FORCE,
899055Seric 	"via",			H_TRACE|H_FORCE,
909055Seric 	"mail-from",		H_TRACE|H_FORCE,
918060Seric 
9258796Seric 		/* miscellaneous fields */
9358796Seric 	"comments",		H_FORCE,
9458796Seric 	"return-path",		H_ACHECK,
9558796Seric 
969055Seric 	NULL,			0,
972897Seric };
984166Seric 
994166Seric 
1004166Seric 
1014282Seric /*
1024282Seric **  Location of system files/databases/etc.
1034282Seric */
1044282Seric 
10540980Sbostic char	*ConfFile =	_PATH_SENDMAILCF;	/* runtime configuration */
10640980Sbostic char	*FreezeFile =	_PATH_SENDMAILFC;	/* frozen version of above */
10758082Seric char	*PidFile =	_PATH_SENDMAILPID;	/* stores daemon proc id */
1089039Seric 
1099064Seric 
1109064Seric 
1119039Seric /*
11258082Seric **  Privacy values
11358082Seric */
11458082Seric 
11558082Seric struct prival PrivacyValues[] =
11658082Seric {
11758082Seric 	"public",		PRIV_PUBLIC,
11858082Seric 	"needmailhelo",		PRIV_NEEDMAILHELO,
11958114Seric 	"needexpnhelo",		PRIV_NEEDEXPNHELO,
12058082Seric 	"needvrfyhelo",		PRIV_NEEDVRFYHELO,
12158082Seric 	"noexpn",		PRIV_NOEXPN,
12258082Seric 	"novrfy",		PRIV_NOVRFY,
12358249Seric 	"restrictmailq",	PRIV_RESTRMAILQ,
12458789Seric 	"authwarnings",		PRIV_AUTHWARNINGS,
12558082Seric 	"goaway",		PRIV_GOAWAY,
12658789Seric 	NULL,			0,
12758082Seric };
12858082Seric 
12958082Seric 
13058082Seric 
13158082Seric /*
13224943Seric **  Miscellaneous stuff.
1339039Seric */
1349039Seric 
13524943Seric int	DtableSize =	50;		/* max open files; reset in 4.2bsd */
13624943Seric /*
13724943Seric **  SETDEFAULTS -- set default values
13824943Seric **
13924943Seric **	Because of the way freezing is done, these must be initialized
14024943Seric **	using direct code.
14124943Seric **
14224943Seric **	Parameters:
14358734Seric **		e -- the default envelope.
14424943Seric **
14524943Seric **	Returns:
14624943Seric **		none.
14724943Seric **
14824943Seric **	Side Effects:
14924943Seric **		Initializes a bunch of global variables to their
15024943Seric **		default values.
15124943Seric */
15224943Seric 
15358737Seric #define DAYS		* 24 * 60 * 60
15458737Seric 
15558734Seric setdefaults(e)
15658734Seric 	register ENVELOPE *e;
15724943Seric {
15857438Seric 	SpaceSub = ' ';				/* option B */
15957438Seric 	QueueLA = 8;				/* option x */
16057438Seric 	RefuseLA = 12;				/* option X */
16157438Seric 	WkRecipFact = 30000L;			/* option y */
16257438Seric 	WkClassFact = 1800L;			/* option z */
16357438Seric 	WkTimeFact = 90000L;			/* option Z */
16457438Seric 	QueueFactor = WkRecipFact * 20;		/* option q */
16557142Seric 	FileMode = (getuid() != geteuid()) ? 0644 : 0600;
16657438Seric 						/* option F */
16757438Seric 	DefUid = 1;				/* option u */
16857438Seric 	DefGid = 1;				/* option g */
16957438Seric 	CheckpointInterval = 10;		/* option C */
17057438Seric 	MaxHopCount = 25;			/* option h */
17158734Seric 	e->e_sendmode = SM_FORK;		/* option d */
17258734Seric 	e->e_errormode = EM_PRINT;		/* option e */
17359709Seric 	SevenBit = FALSE;			/* option 7 */
17457438Seric 	MaxMciCache = 1;			/* option k */
17557438Seric 	MciCacheTimeout = 300;			/* option K */
17657438Seric 	LogLevel = 9;				/* option L */
17758112Seric 	settimeouts(NULL);			/* option r */
17858737Seric 	TimeOuts.to_q_return = 5 DAYS;		/* option T */
17958737Seric 	TimeOuts.to_q_warning = 0;		/* option T */
18058853Seric 	PrivacyFlags = 0;			/* option p */
18140973Sbostic 	setdefuser();
18253654Seric 	setupmaps();
18357402Seric 	setupmailers();
18424943Seric }
185294Seric 
18640973Sbostic 
1874326Seric /*
18840973Sbostic **  SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
18940973Sbostic */
19040973Sbostic 
19140973Sbostic setdefuser()
19240973Sbostic {
19340973Sbostic 	struct passwd *defpwent;
19457386Seric 	static char defuserbuf[40];
19540973Sbostic 
19657386Seric 	DefUser = defuserbuf;
19740973Sbostic 	if ((defpwent = getpwuid(DefUid)) != NULL)
19857386Seric 		strcpy(defuserbuf, defpwent->pw_name);
19940973Sbostic 	else
20057386Seric 		strcpy(defuserbuf, "nobody");
20140973Sbostic }
20253654Seric /*
20356836Seric **  HOST_MAP_INIT -- initialize host class structures
20456836Seric */
20556836Seric 
20656836Seric bool
20756836Seric host_map_init(map, mapname, args)
20856836Seric 	MAP *map;
20956836Seric 	char *mapname;
21056836Seric 	char *args;
21156836Seric {
21256836Seric 	register char *p = args;
21356836Seric 
21456836Seric 	for (;;)
21556836Seric 	{
21658050Seric 		while (isascii(*p) && isspace(*p))
21756836Seric 			p++;
21856836Seric 		if (*p != '-')
21956836Seric 			break;
22056836Seric 		switch (*++p)
22156836Seric 		{
22256836Seric 		  case 'a':
22356836Seric 			map->map_app = ++p;
22456836Seric 			break;
22556836Seric 		}
22658050Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
22756836Seric 			p++;
22856836Seric 		if (*p != '\0')
22956836Seric 			*p++ = '\0';
23056836Seric 	}
23156836Seric 	if (map->map_app != NULL)
23256836Seric 		map->map_app = newstr(map->map_app);
23356836Seric 	return TRUE;
23456836Seric }
23557402Seric /*
23657402Seric **  SETUPMAILERS -- initialize default mailers
23757402Seric */
23856836Seric 
23957402Seric setupmailers()
24057402Seric {
24157402Seric 	char buf[100];
24257402Seric 
24357403Seric 	strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u");
24457403Seric 	makemailer(buf);
24557403Seric 
24659883Seric 	strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE");
24757402Seric 	makemailer(buf);
24857402Seric 
24957402Seric 	strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE");
25057402Seric 	makemailer(buf);
25157402Seric }
25256836Seric /*
2534326Seric **  GETRUID -- get real user id (V7)
2544326Seric */
2554326Seric 
2564326Seric getruid()
2574326Seric {
2589274Seric 	if (OpMode == MD_DAEMON)
2594536Seric 		return (RealUid);
2604536Seric 	else
2614536Seric 		return (getuid());
2624326Seric }
2634326Seric 
2644326Seric 
2654326Seric /*
2664326Seric **  GETRGID -- get real group id (V7).
2674326Seric */
2684326Seric 
2694326Seric getrgid()
2704326Seric {
2719274Seric 	if (OpMode == MD_DAEMON)
2724536Seric 		return (RealGid);
2734536Seric 	else
2744536Seric 		return (getgid());
2754326Seric }
27653654Seric /*
2779369Seric **  USERNAME -- return the user id of the logged in user.
2789369Seric **
2799369Seric **	Parameters:
2809369Seric **		none.
2819369Seric **
2829369Seric **	Returns:
2839369Seric **		The login name of the logged in user.
2849369Seric **
2859369Seric **	Side Effects:
2869369Seric **		none.
2879369Seric **
2889369Seric **	Notes:
2899369Seric **		The return value is statically allocated.
2909369Seric */
2919369Seric 
2929369Seric char *
2939369Seric username()
2949369Seric {
29517469Seric 	static char *myname = NULL;
2969369Seric 	extern char *getlogin();
29719904Smiriam 	register struct passwd *pw;
2989369Seric 
29917469Seric 	/* cache the result */
30017469Seric 	if (myname == NULL)
30117469Seric 	{
30217469Seric 		myname = getlogin();
30317469Seric 		if (myname == NULL || myname[0] == '\0')
30417469Seric 		{
30517469Seric 			pw = getpwuid(getruid());
30617469Seric 			if (pw != NULL)
30740993Sbostic 				myname = newstr(pw->pw_name);
30817469Seric 		}
30919904Smiriam 		else
31019904Smiriam 		{
31158736Seric 			uid_t uid = getuid();
31219873Smiriam 
31340993Sbostic 			myname = newstr(myname);
31440993Sbostic 			if ((pw = getpwnam(myname)) == NULL ||
31558736Seric 			      (uid != 0 && uid != pw->pw_uid))
31619904Smiriam 			{
31758736Seric 				pw = getpwuid(uid);
31824945Seric 				if (pw != NULL)
31940993Sbostic 					myname = newstr(pw->pw_name);
32019873Smiriam 			}
32119873Smiriam 		}
32217469Seric 		if (myname == NULL || myname[0] == '\0')
32317469Seric 		{
32458151Seric 			syserr("554 Who are you?");
32517469Seric 			myname = "postmaster";
32617469Seric 		}
32717469Seric 	}
32817469Seric 
32917469Seric 	return (myname);
3309369Seric }
3319369Seric /*
3324190Seric **  TTYPATH -- Get the path of the user's tty
333294Seric **
334294Seric **	Returns the pathname of the user's tty.  Returns NULL if
335294Seric **	the user is not logged in or if s/he has write permission
336294Seric **	denied.
337294Seric **
338294Seric **	Parameters:
339294Seric **		none
340294Seric **
341294Seric **	Returns:
342294Seric **		pathname of the user's tty.
343294Seric **		NULL if not logged in or write permission denied.
344294Seric **
345294Seric **	Side Effects:
346294Seric **		none.
347294Seric **
348294Seric **	WARNING:
349294Seric **		Return value is in a local buffer.
350294Seric **
351294Seric **	Called By:
352294Seric **		savemail
353294Seric */
354294Seric 
355294Seric char *
356294Seric ttypath()
357294Seric {
358294Seric 	struct stat stbuf;
359294Seric 	register char *pathn;
360294Seric 	extern char *ttyname();
3614081Seric 	extern char *getlogin();
362294Seric 
363294Seric 	/* compute the pathname of the controlling tty */
3649369Seric 	if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
3659369Seric 	    (pathn = ttyname(0)) == NULL)
366294Seric 	{
367294Seric 		errno = 0;
368294Seric 		return (NULL);
369294Seric 	}
370294Seric 
371294Seric 	/* see if we have write permission */
3722967Seric 	if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
373294Seric 	{
374294Seric 		errno = 0;
375294Seric 		return (NULL);
376294Seric 	}
377294Seric 
378294Seric 	/* see if the user is logged in */
379294Seric 	if (getlogin() == NULL)
380294Seric 		return (NULL);
381294Seric 
382294Seric 	/* looks good */
383294Seric 	return (pathn);
384294Seric }
3852967Seric /*
3862967Seric **  CHECKCOMPAT -- check for From and To person compatible.
3872967Seric **
3882967Seric **	This routine can be supplied on a per-installation basis
3892967Seric **	to determine whether a person is allowed to send a message.
3902967Seric **	This allows restriction of certain types of internet
3912967Seric **	forwarding or registration of users.
3922967Seric **
3932967Seric **	If the hosts are found to be incompatible, an error
39457454Seric **	message should be given using "usrerr" and 0 should
3952967Seric **	be returned.
3962967Seric **
3974288Seric **	'NoReturn' can be set to suppress the return-to-sender
3984288Seric **	function; this should be done on huge messages.
3994288Seric **
4002967Seric **	Parameters:
4012967Seric **		to -- the person being sent to.
4022967Seric **
4032967Seric **	Returns:
40457459Seric **		an exit status
4052967Seric **
4062967Seric **	Side Effects:
4072967Seric **		none (unless you include the usrerr stuff)
4082967Seric */
4092967Seric 
41055012Seric checkcompat(to, e)
4112967Seric 	register ADDRESS *to;
41255012Seric 	register ENVELOPE *e;
4132967Seric {
41412133Seric # ifdef lint
41512133Seric 	if (to == NULL)
41612133Seric 		to++;
41712133Seric # endif lint
41810698Seric # ifdef EXAMPLE_CODE
41910698Seric 	/* this code is intended as an example only */
4204437Seric 	register STAB *s;
4214437Seric 
4224437Seric 	s = stab("arpa", ST_MAILER, ST_FIND);
42355012Seric 	if (s != NULL && e->e_from.q_mailer != LocalMailer &&
4249369Seric 	    to->q_mailer == s->s_mailer)
4254437Seric 	{
42658151Seric 		usrerr("553 No ARPA mail through this machine: see your system administration");
42710698Seric 		/* NoReturn = TRUE; to supress return copy */
42857459Seric 		return (EX_UNAVAILABLE);
4294437Seric 	}
43056795Seric # endif /* EXAMPLE_CODE */
43157459Seric 	return (EX_OK);
4322967Seric }
4339369Seric /*
4349369Seric **  HOLDSIGS -- arrange to hold all signals
4359369Seric **
4369369Seric **	Parameters:
4379369Seric **		none.
4389369Seric **
4399369Seric **	Returns:
4409369Seric **		none.
4419369Seric **
4429369Seric **	Side Effects:
4439369Seric **		Arranges that signals are held.
4449369Seric */
4459369Seric 
4469369Seric holdsigs()
4479369Seric {
4489369Seric }
4499369Seric /*
4509369Seric **  RLSESIGS -- arrange to release all signals
4519369Seric **
4529369Seric **	This undoes the effect of holdsigs.
4539369Seric **
4549369Seric **	Parameters:
4559369Seric **		none.
4569369Seric **
4579369Seric **	Returns:
4589369Seric **		none.
4599369Seric **
4609369Seric **	Side Effects:
4619369Seric **		Arranges that signals are released.
4629369Seric */
4639369Seric 
4649369Seric rlsesigs()
4659369Seric {
4669369Seric }
46714872Seric /*
46814872Seric **  GETLA -- get the current load average
46914872Seric **
47014881Seric **	This code stolen from la.c.
47114881Seric **
47214872Seric **	Parameters:
47314872Seric **		none.
47414872Seric **
47514872Seric **	Returns:
47614872Seric **		The current load average as an integer.
47714872Seric **
47814872Seric **	Side Effects:
47914872Seric **		none.
48014872Seric */
48114872Seric 
48251920Seric /* try to guess what style of load average we have */
48351920Seric #define LA_ZERO		1	/* always return load average as zero */
48451920Seric #define LA_INT		2	/* read kmem for avenrun; interpret as int */
48551920Seric #define LA_FLOAT	3	/* read kmem for avenrun; interpret as float */
48651920Seric #define LA_SUBR		4	/* call getloadavg */
48714872Seric 
48851920Seric #ifndef LA_TYPE
489*60160Seric #  if defined(sun) && !defined(BSD)
49051920Seric #    define LA_TYPE		LA_INT
49151920Seric #  endif
49257977Seric #  if defined(mips) || defined(__alpha)
49357977Seric      /* Ultrix or OSF/1 or RISC/os */
49451920Seric #    define LA_TYPE		LA_INT
49551920Seric #    define LA_AVENRUN		"avenrun"
49651920Seric #  endif
49759430Seric #  if defined(__hpux)
49851920Seric #    define LA_TYPE		LA_FLOAT
49959253Seric #    define LA_AVENRUN		"avenrun"
50051920Seric #  endif
50151920Seric 
50251920Seric #  ifndef LA_TYPE
50357736Seric #   if defined(SYSTEM5)
50457736Seric #    define LA_TYPE		LA_INT
50557736Seric #    define LA_AVENRUN		"avenrun"
50657736Seric #   else
50757736Seric #    if defined(BSD)
50857736Seric #     define LA_TYPE		LA_SUBR
50957736Seric #    else
51057736Seric #     define LA_TYPE		LA_ZERO
51157736Seric #    endif
51257736Seric #   endif
51351920Seric #  endif
51451920Seric #endif
51551920Seric 
51651920Seric #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT)
51751920Seric 
51814872Seric #include <nlist.h>
51914872Seric 
52051920Seric #ifndef LA_AVENRUN
52151920Seric #define LA_AVENRUN	"_avenrun"
52251920Seric #endif
52351920Seric 
52451920Seric /* _PATH_UNIX should be defined in <paths.h> */
52551920Seric #ifndef _PATH_UNIX
52659430Seric #  if defined(__hpux)
52751920Seric #    define _PATH_UNIX		"/hp-ux"
52851920Seric #  endif
52951920Seric #  if defined(mips) && !defined(ultrix)
53051920Seric      /* powerful RISC/os */
53151920Seric #    define _PATH_UNIX		"/unix"
53251920Seric #  endif
53357736Seric #  if defined(SYSTEM5)
53457977Seric #    ifndef _PATH_UNIX
53557977Seric #      define _PATH_UNIX	"/unix"
53657977Seric #    endif
53757736Seric #  endif
53851920Seric #  ifndef _PATH_UNIX
53951920Seric #    define _PATH_UNIX		"/vmunix"
54051920Seric #  endif
54151920Seric #endif
54251920Seric 
54314872Seric struct	nlist Nl[] =
54414872Seric {
54551920Seric 	{ LA_AVENRUN },
54614872Seric #define	X_AVENRUN	0
54714872Seric 	{ 0 },
54814872Seric };
54914872Seric 
55057736Seric #if defined(unixpc)
55157736Seric # define FSHIFT		5
55257736Seric #endif
55357736Seric 
55457977Seric #if defined(__alpha)
55557977Seric # define FSHIFT		10
55657977Seric #endif
55757977Seric 
55851920Seric #if (LA_TYPE == LA_INT) && !defined(FSHIFT)
55951920Seric #  define FSHIFT	8
56057736Seric #endif
56157736Seric #if (LA_TYPE == LA_INT) && !defined(FSCALE)
56251920Seric #  define FSCALE	(1 << FSHIFT)
56351920Seric #endif
56440930Srick 
56514872Seric getla()
56614872Seric {
56714872Seric 	static int kmem = -1;
56851920Seric #if LA_TYPE == LA_INT
56924943Seric 	long avenrun[3];
57051920Seric #else
57151920Seric 	double avenrun[3];
57251920Seric #endif
57325615Seric 	extern off_t lseek();
57457736Seric 	extern int errno;
57514872Seric 
57614872Seric 	if (kmem < 0)
57714872Seric 	{
57824945Seric 		kmem = open("/dev/kmem", 0, 0);
57914872Seric 		if (kmem < 0)
58057736Seric 		{
58157736Seric 			if (tTd(3, 1))
58257736Seric 				printf("getla: open(/dev/kmem): %s\n",
58357736Seric 					errstring(errno));
58414872Seric 			return (-1);
58557736Seric 		}
58651920Seric 		(void) fcntl(kmem, F_SETFD, 1);
58757736Seric 		if (nlist(_PATH_UNIX, Nl) < 0)
58857736Seric 		{
58957736Seric 			if (tTd(3, 1))
59057736Seric 				printf("getla: nlist(%s): %s\n", _PATH_UNIX,
59157736Seric 					errstring(errno));
59214872Seric 			return (-1);
59357736Seric 		}
59459253Seric 		if (Nl[X_AVENRUN].n_value == 0)
59559253Seric 		{
59659253Seric 			if (tTd(3, 1))
59759253Seric 				printf("getla: nlist(%s, %s) ==> 0\n",
59859253Seric 					_PATH_UNIX, LA_AVENRUN);
59959253Seric 			return (-1);
60059253Seric 		}
60114872Seric 	}
60257736Seric 	if (tTd(3, 20))
60357736Seric 		printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value);
60424945Seric 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
60523118Seric 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
60619967Seric 	{
60719967Seric 		/* thank you Ian */
60857736Seric 		if (tTd(3, 1))
60957736Seric 			printf("getla: lseek or read: %s\n", errstring(errno));
61019967Seric 		return (-1);
61119967Seric 	}
61251920Seric #if LA_TYPE == LA_INT
61357736Seric 	if (tTd(3, 5))
61457736Seric 	{
61557736Seric 		printf("getla: avenrun = %d", avenrun[0]);
61657736Seric 		if (tTd(3, 15))
61757736Seric 			printf(", %d, %d", avenrun[1], avenrun[2]);
61857736Seric 		printf("\n");
61957736Seric 	}
62057736Seric 	if (tTd(3, 1))
62157736Seric 		printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
62224943Seric 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
62351920Seric #else
62457736Seric 	if (tTd(3, 5))
62557736Seric 	{
62657736Seric 		printf("getla: avenrun = %g", avenrun[0]);
62757736Seric 		if (tTd(3, 15))
62857736Seric 			printf(", %g, %g", avenrun[1], avenrun[2]);
62957736Seric 		printf("\n");
63057736Seric 	}
63157736Seric 	if (tTd(3, 1))
63257736Seric 		printf("getla: %d\n", (int) (avenrun[0] +0.5));
63351920Seric 	return ((int) (avenrun[0] + 0.5));
63451920Seric #endif
63514872Seric }
63614872Seric 
63751773Seric #else
63851920Seric #if LA_TYPE == LA_SUBR
63951773Seric 
64051773Seric getla()
64151773Seric {
64251920Seric 	double avenrun[3];
64351920Seric 
64451920Seric 	if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
64557736Seric 	{
64657736Seric 		if (tTd(3, 1))
64757736Seric 			perror("getla: getloadavg failed:");
64851920Seric 		return (-1);
64957736Seric 	}
65057736Seric 	if (tTd(3, 1))
65157736Seric 		printf("getla: %d\n", (int) (avenrun[0] +0.5));
65251920Seric 	return ((int) (avenrun[0] + 0.5));
65351773Seric }
65451773Seric 
65551773Seric #else
65651773Seric 
65751773Seric getla()
65851773Seric {
65957736Seric 	if (tTd(3, 1))
66057736Seric 		printf("getla: ZERO\n");
66151920Seric 	return (0);
66251773Seric }
66351773Seric 
66451773Seric #endif
66551773Seric #endif
66624943Seric /*
66724943Seric **  SHOULDQUEUE -- should this message be queued or sent?
66824943Seric **
66924943Seric **	Compares the message cost to the load average to decide.
67024943Seric **
67124943Seric **	Parameters:
67224943Seric **		pri -- the priority of the message in question.
67357438Seric **		ctime -- the message creation time.
67424943Seric **
67524943Seric **	Returns:
67624943Seric **		TRUE -- if this message should be queued up for the
67724943Seric **			time being.
67824943Seric **		FALSE -- if the load is low enough to send this message.
67924943Seric **
68024943Seric **	Side Effects:
68124943Seric **		none.
68224943Seric */
68324943Seric 
68424943Seric bool
68557438Seric shouldqueue(pri, ctime)
68624943Seric 	long pri;
68757438Seric 	time_t ctime;
68824943Seric {
68951920Seric 	if (CurrentLA < QueueLA)
69024943Seric 		return (FALSE);
69158132Seric 	if (CurrentLA >= RefuseLA)
69258132Seric 		return (TRUE);
69351920Seric 	return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
69424943Seric }
69524943Seric /*
69653037Seric **  REFUSECONNECTIONS -- decide if connections should be refused
69753037Seric **
69853037Seric **	Parameters:
69953037Seric **		none.
70053037Seric **
70153037Seric **	Returns:
70253037Seric **		TRUE if incoming SMTP connections should be refused
70353037Seric **			(for now).
70453037Seric **		FALSE if we should accept new work.
70553037Seric **
70653037Seric **	Side Effects:
70753037Seric **		none.
70853037Seric */
70953037Seric 
71053037Seric bool
71153037Seric refuseconnections()
71253037Seric {
71359156Seric #ifdef XLA
71459156Seric 	if (!xla_smtp_ok())
71559156Seric 		return TRUE;
71659156Seric #endif
71759156Seric 
71853037Seric 	/* this is probably too simplistic */
71958132Seric 	return (CurrentLA >= RefuseLA);
72053037Seric }
72153037Seric /*
72224943Seric **  SETPROCTITLE -- set process title for ps
72324943Seric **
72424943Seric **	Parameters:
72558674Seric **		fmt -- a printf style format string.
72658674Seric **		a, b, c -- possible parameters to fmt.
72724943Seric **
72824943Seric **	Returns:
72924943Seric **		none.
73024943Seric **
73124943Seric **	Side Effects:
73224943Seric **		Clobbers argv of our main procedure so ps(1) will
73324943Seric **		display the title.
73424943Seric */
73524943Seric 
73658689Seric #ifdef SETPROCTITLE
73758689Seric # ifdef __hpux
73858689Seric #  include <sys/pstat.h>
73958689Seric # endif
74059732Seric # ifdef BSD4_4
74159732Seric #  include <machine/vmparam.h>
74259732Seric #  include <sys/exec.h>
74359992Seric #  ifdef PS_STRINGS
74459992Seric #   define SETPROC_STATIC static
74559992Seric #  endif
74659732Seric # endif
74759732Seric # ifndef SETPROC_STATIC
74859732Seric #  define SETPROC_STATIC
74959732Seric # endif
75058689Seric #endif
75158689Seric 
75224943Seric /*VARARGS1*/
75357642Seric #ifdef __STDC__
75457642Seric setproctitle(char *fmt, ...)
75557642Seric #else
75657642Seric setproctitle(fmt, va_alist)
75724943Seric 	char *fmt;
75857642Seric 	va_dcl
75957642Seric #endif
76024943Seric {
76124943Seric # ifdef SETPROCTITLE
76224943Seric 	register char *p;
76325049Seric 	register int i;
76459732Seric 	SETPROC_STATIC char buf[MAXLINE];
76556852Seric 	VA_LOCAL_DECL
76658689Seric #  ifdef __hpux
76758689Seric 	union pstun pst;
76858689Seric #  endif
76924943Seric 	extern char **Argv;
77024943Seric 	extern char *LastArgv;
77124943Seric 
77258674Seric 	p = buf;
77324943Seric 
77458674Seric 	/* print sendmail: heading for grep */
77558674Seric 	(void) strcpy(p, "sendmail: ");
77658674Seric 	p += strlen(p);
77724943Seric 
77858674Seric 	/* print the argument string */
77958674Seric 	VA_START(fmt);
78058674Seric 	(void) vsprintf(p, fmt, ap);
78156852Seric 	VA_END;
78254996Seric 
78358674Seric 	i = strlen(buf);
78458689Seric 
78558689Seric #  ifdef __hpux
78658689Seric 	pst.pst_command = buf;
78758689Seric 	pstat(PSTAT_SETCMD, pst, i, 0, 0);
78858689Seric #  else
78959992Seric #   ifdef PS_STRINGS
79059732Seric 	PS_STRINGS->ps_nargvstr = 1;
79159732Seric 	PS_STRINGS->ps_argvstr = buf;
79259732Seric #   else
79354996Seric 	if (i > LastArgv - Argv[0] - 2)
79425049Seric 	{
79554996Seric 		i = LastArgv - Argv[0] - 2;
79658674Seric 		buf[i] = '\0';
79725049Seric 	}
79858674Seric 	(void) strcpy(Argv[0], buf);
79954997Seric 	p = &Argv[0][i];
80024943Seric 	while (p < LastArgv)
80124943Seric 		*p++ = ' ';
80259732Seric #   endif
80358689Seric #  endif
80456795Seric # endif /* SETPROCTITLE */
80524943Seric }
80625698Seric /*
80725698Seric **  REAPCHILD -- pick up the body of my child, lest it become a zombie
80825698Seric **
80925698Seric **	Parameters:
81025698Seric **		none.
81125698Seric **
81225698Seric **	Returns:
81325698Seric **		none.
81425698Seric **
81525698Seric **	Side Effects:
81625698Seric **		Picks up extant zombies.
81725698Seric */
81825698Seric 
81925698Seric # include <sys/wait.h>
82025698Seric 
82146928Sbostic void
82225698Seric reapchild()
82325698Seric {
82425698Seric # ifdef WNOHANG
82525698Seric 	union wait status;
82625698Seric 
82746928Sbostic 	while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
82825698Seric 		continue;
82956795Seric # else /* WNOHANG */
83025698Seric 	auto int status;
83125698Seric 
83246928Sbostic 	while (wait((int *)&status) > 0)
83325698Seric 		continue;
83456795Seric # endif /* WNOHANG */
83558061Seric # ifdef SYSTEM5
83658061Seric 	(void) signal(SIGCHLD, reapchild);
83758061Seric # endif
83825698Seric }
83955418Seric /*
84055418Seric **  UNSETENV -- remove a variable from the environment
84155418Seric **
84255418Seric **	Not needed on newer systems.
84355418Seric **
84455418Seric **	Parameters:
84555418Seric **		name -- the string name of the environment variable to be
84655418Seric **			deleted from the current environment.
84755418Seric **
84855418Seric **	Returns:
84955418Seric **		none.
85055418Seric **
85155418Seric **	Globals:
85255418Seric **		environ -- a pointer to the current environment.
85355418Seric **
85455418Seric **	Side Effects:
85555418Seric **		Modifies environ.
85655418Seric */
85755418Seric 
85855418Seric #ifdef UNSETENV
85955418Seric 
86055418Seric void
86155418Seric unsetenv(name)
86255418Seric 	char *name;
86355418Seric {
86455418Seric 	extern char **environ;
86555418Seric 	register char **pp;
86655418Seric 	int len = strlen(name);
86755418Seric 
86855418Seric 	for (pp = environ; *pp != NULL; pp++)
86955418Seric 	{
87055418Seric 		if (strncmp(name, *pp, len) == 0 &&
87155418Seric 		    ((*pp)[len] == '=' || (*pp)[len] == '\0'))
87255418Seric 			break;
87355418Seric 	}
87455418Seric 
87555418Seric 	for (; *pp != NULL; pp++)
87655418Seric 		*pp = pp[1];
87755418Seric }
87855418Seric 
87955418Seric #endif /* UNSETENV */
88056215Seric /*
88156215Seric **  GETDTABLESIZE -- return number of file descriptors
88256215Seric **
88356215Seric **	Only on non-BSD systems
88456215Seric **
88556215Seric **	Parameters:
88656215Seric **		none
88756215Seric **
88856215Seric **	Returns:
88956215Seric **		size of file descriptor table
89056215Seric **
89156215Seric **	Side Effects:
89256215Seric **		none
89356215Seric */
89456215Seric 
89556215Seric #ifdef SYSTEM5
89656215Seric 
89756215Seric int
89856215Seric getdtablesize()
89956215Seric {
90058689Seric # ifdef _SC_OPEN_MAX
90158689Seric 	return sysconf(_SC_OPEN_MAX);
90258689Seric # else
90356215Seric 	return NOFILE;
90458689Seric # endif
90556215Seric }
90656215Seric 
90756215Seric #endif
90857631Seric /*
90957631Seric **  UNAME -- get the UUCP name of this system.
91057631Seric */
91157631Seric 
91257943Seric #ifndef HASUNAME
91357631Seric 
91457631Seric int
91557631Seric uname(name)
91657631Seric 	struct utsname *name;
91757631Seric {
91857631Seric 	FILE *file;
91957631Seric 	char *n;
92057631Seric 
92157631Seric 	name->nodename[0] = '\0';
92257631Seric 
92357661Seric 	/* try /etc/whoami -- one line with the node name */
92457631Seric 	if ((file = fopen("/etc/whoami", "r")) != NULL)
92557631Seric 	{
92657661Seric 		(void) fgets(name->nodename, NODE_LENGTH + 1, file);
92757631Seric 		(void) fclose(file);
92857661Seric 		n = strchr(name->nodename, '\n');
92957631Seric 		if (n != NULL)
93057631Seric 			*n = '\0';
93157631Seric 		if (name->nodename[0] != '\0')
93257631Seric 			return (0);
93357631Seric 	}
93457631Seric 
93557661Seric 	/* try /usr/include/whoami.h -- has a #define somewhere */
93657631Seric 	if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
93757631Seric 	{
93857631Seric 		char buf[MAXLINE];
93957631Seric 
94057631Seric 		while (fgets(buf, MAXLINE, file) != NULL)
94157631Seric 			if (sscanf(buf, "#define sysname \"%*[^\"]\"",
94257631Seric 					NODE_LENGTH, name->nodename) > 0)
94357631Seric 				break;
94457631Seric 		(void) fclose(file);
94557631Seric 		if (name->nodename[0] != '\0')
94657631Seric 			return (0);
94757631Seric 	}
94857631Seric 
94957631Seric #ifdef TRUST_POPEN
95057631Seric 	/*
95157631Seric 	**  Popen is known to have security holes.
95257631Seric 	*/
95357631Seric 
95457661Seric 	/* try uuname -l to return local name */
95557631Seric 	if ((file = popen("uuname -l", "r")) != NULL)
95657631Seric 	{
95757661Seric 		(void) fgets(name, NODE_LENGTH + 1, file);
95857631Seric 		(void) pclose(file);
95957661Seric 		n = strchr(name, '\n');
96057631Seric 		if (n != NULL)
96157631Seric 			*n = '\0';
96257661Seric 		if (name->nodename[0] != '\0')
96357631Seric 			return (0);
96457631Seric 	}
96557631Seric #endif
96657631Seric 
96757631Seric 	return (-1);
96857631Seric }
96957943Seric #endif /* HASUNAME */
97058068Seric /*
97158068Seric **  INITGROUPS -- initialize groups
97258068Seric **
97358068Seric **	Stub implementation for System V style systems
97458068Seric */
97558068Seric 
97658068Seric #ifndef HASINITGROUPS
97759430Seric # if !defined(SYSTEM5) || defined(__hpux)
97858068Seric #  define HASINITGROUPS
97958068Seric # endif
98058068Seric #endif
98158068Seric 
98258068Seric #ifndef HASINITGROUPS
98358068Seric 
98458068Seric initgroups(name, basegid)
98558068Seric 	char *name;
98658068Seric 	int basegid;
98758068Seric {
98858068Seric 	return 0;
98958068Seric }
99058068Seric 
99158068Seric #endif
99258082Seric /*
99359289Seric **  SETSID -- set session id (for non-POSIX systems)
99459289Seric */
99559289Seric 
99659289Seric #ifndef HASSETSID
99759289Seric 
99859289Seric setsid()
99959289Seric {
100059289Seric # ifdef SYSTEM5
100159289Seric 	setpgrp();
100259289Seric # endif
100359289Seric }
100459289Seric 
100559289Seric #endif
100659289Seric /*
100758082Seric **  ENOUGHSPACE -- check to see if there is enough free space on the queue fs
100858082Seric **
100958082Seric **	Only implemented if you have statfs.
101058082Seric **
101158082Seric **	Parameters:
101258333Seric **		msize -- the size to check against.  If zero, we don't yet
101358333Seric **			know how big the message will be, so just check for
101458333Seric **			a "reasonable" amount.
101558082Seric **
101658082Seric **	Returns:
101758082Seric **		TRUE if there is enough space.
101858082Seric **		FALSE otherwise.
101958082Seric */
102058082Seric 
102158082Seric #ifndef HASSTATFS
102258082Seric # if defined(BSD4_4) || defined(__osf__)
102358082Seric #  define HASSTATFS
102458082Seric # endif
102558082Seric #endif
102658082Seric 
102758082Seric #ifdef HASSTATFS
102858157Seric # undef HASUSTAT
102958157Seric #endif
103058157Seric 
103158157Seric #if defined(HASUSTAT)
103258157Seric # include <ustat.h>
103358157Seric #endif
103458157Seric 
103558157Seric #ifdef HASSTATFS
103658133Seric # if defined(sgi) || defined(apollo)
103758133Seric #  include <sys/statfs.h>
103858133Seric # else
1039*60160Seric #  if (defined(sun) && !defined(BSD)) || defined(__hpux)
104058133Seric #   include <sys/vfs.h>
104158133Seric #  else
104258157Seric #   include <sys/mount.h>
104358133Seric #  endif
104458133Seric # endif
104558082Seric #endif
104658082Seric 
104758082Seric bool
104858333Seric enoughspace(msize)
104958333Seric 	long msize;
105058082Seric {
105158160Seric #if defined(HASSTATFS) || defined(HASUSTAT)
105258157Seric # if defined(HASUSTAT)
105358153Seric 	struct ustat fs;
105458153Seric 	struct stat statbuf;
105558366Seric #  define FSBLOCKSIZE	DEV_BSIZE
105658157Seric #  define f_bavail	f_tfree
105758157Seric # else
105858157Seric #  if defined(ultrix)
105958157Seric 	struct fs_data fs;
106058157Seric #   define f_bavail	fd_bfreen
106158366Seric #   define FSBLOCKSIZE	fs.fd_bsize
106258153Seric #  else
106358082Seric 	struct statfs fs;
106458366Seric #   define FSBLOCKSIZE	fs.f_bsize
106558153Seric #  endif
106658133Seric # endif
106758333Seric 	long blocksneeded;
106858082Seric 	extern int errno;
106958082Seric 
107058333Seric 	if (MinBlocksFree <= 0 && msize <= 0)
107158082Seric 	{
107258082Seric 		if (tTd(4, 80))
107358133Seric 			printf("enoughspace: no threshold\n");
107458133Seric 		return TRUE;
107558133Seric 	}
107658333Seric 
107758157Seric # if defined(HASUSTAT)
107858157Seric 	if (stat(QueueDir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
107958157Seric # else
108058157Seric #  if defined(sgi) || defined(apollo)
108158133Seric 	if (statfs(QueueDir, &fs, sizeof fs, 0) == 0)
108258157Seric #  else
108358157Seric #   if defined(ultrix)
108458133Seric 	if (statfs(QueueDir, &fs) > 0)
108558153Seric #   else
108658133Seric 	if (statfs(QueueDir, &fs) == 0)
108758153Seric #   endif
108858133Seric #  endif
108958133Seric # endif
109058133Seric 	{
109158133Seric 		if (tTd(4, 80))
109258333Seric 			printf("enoughspace: bavail=%ld, need=%ld\n",
109358333Seric 				fs.f_bavail, msize);
109458333Seric 
109558333Seric 		/* convert msize to block count */
109658366Seric 		msize = msize / FSBLOCKSIZE + 1;
109758333Seric 		if (MinBlocksFree >= 0)
109858333Seric 			msize += MinBlocksFree;
109958333Seric 
110058333Seric 		if (fs.f_bavail < msize)
110158090Seric 		{
110258090Seric #ifdef LOG
110358090Seric 			if (LogLevel > 0)
110458090Seric 				syslog(LOG_ALERT, "%s: low on space (have %ld, need %ld)",
110558333Seric 					QueueDir, fs.f_bavail, msize);
110658090Seric #endif
110758082Seric 			return FALSE;
110858090Seric 		}
110958082Seric 	}
111058082Seric 	else if (tTd(4, 80))
111158333Seric 		printf("enoughspace failure: min=%ld, need=%ld: %s\n",
111258333Seric 			MinBlocksFree, msize, errstring(errno));
111358082Seric #endif
111458082Seric 	return TRUE;
111558082Seric }
111658542Seric /*
111758542Seric **  TRANSIENTERROR -- tell if an error code indicates a transient failure
111858542Seric **
111958542Seric **	This looks at an errno value and tells if this is likely to
112058542Seric **	go away if retried later.
112158542Seric **
112258542Seric **	Parameters:
112358542Seric **		err -- the errno code to classify.
112458542Seric **
112558542Seric **	Returns:
112658542Seric **		TRUE if this is probably transient.
112758542Seric **		FALSE otherwise.
112858542Seric */
112958542Seric 
113058542Seric bool
113158542Seric transienterror(err)
113258542Seric 	int err;
113358542Seric {
113458542Seric 	switch (err)
113558542Seric 	{
113658542Seric 	  case EIO:			/* I/O error */
113758542Seric 	  case ENXIO:			/* Device not configured */
113858542Seric 	  case EAGAIN:			/* Resource temporarily unavailable */
113958542Seric 	  case ENOMEM:			/* Cannot allocate memory */
114058542Seric 	  case ENODEV:			/* Operation not supported by device */
114158542Seric 	  case ENFILE:			/* Too many open files in system */
114258542Seric 	  case EMFILE:			/* Too many open files */
114358542Seric 	  case ENOSPC:			/* No space left on device */
114458542Seric #ifdef ETIMEDOUT
114558542Seric 	  case ETIMEDOUT:		/* Connection timed out */
114658542Seric #endif
114758542Seric #ifdef ESTALE
114858542Seric 	  case ESTALE:			/* Stale NFS file handle */
114958542Seric #endif
115058542Seric #ifdef ENETDOWN
115158542Seric 	  case ENETDOWN:		/* Network is down */
115258542Seric #endif
115358542Seric #ifdef ENETUNREACH
115458542Seric 	  case ENETUNREACH:		/* Network is unreachable */
115558542Seric #endif
115658542Seric #ifdef ENETRESET
115758542Seric 	  case ENETRESET:		/* Network dropped connection on reset */
115858542Seric #endif
115958542Seric #ifdef ECONNABORTED
116058542Seric 	  case ECONNABORTED:		/* Software caused connection abort */
116158542Seric #endif
116258542Seric #ifdef ECONNRESET
116358542Seric 	  case ECONNRESET:		/* Connection reset by peer */
116458542Seric #endif
116558542Seric #ifdef ENOBUFS
116658542Seric 	  case ENOBUFS:			/* No buffer space available */
116758542Seric #endif
116858542Seric #ifdef ESHUTDOWN
116958542Seric 	  case ESHUTDOWN:		/* Can't send after socket shutdown */
117058542Seric #endif
117158542Seric #ifdef ECONNREFUSED
117258542Seric 	  case ECONNREFUSED:		/* Connection refused */
117358542Seric #endif
117458542Seric #ifdef EHOSTDOWN
117558542Seric 	  case EHOSTDOWN:		/* Host is down */
117658542Seric #endif
117758542Seric #ifdef EHOSTUNREACH
117858542Seric 	  case EHOSTUNREACH:		/* No route to host */
117958542Seric #endif
118058542Seric #ifdef EDQUOT
118158542Seric 	  case EDQUOT:			/* Disc quota exceeded */
118258542Seric #endif
118358542Seric #ifdef EPROCLIM
118458542Seric 	  case EPROCLIM:		/* Too many processes */
118558542Seric #endif
118658542Seric #ifdef EUSERS
118758542Seric 	  case EUSERS:			/* Too many users */
118858542Seric #endif
118958542Seric #ifdef EDEADLK
119058542Seric 	  case EDEADLK:			/* Resource deadlock avoided */
119158542Seric #endif
119258542Seric #ifdef EISCONN
119358542Seric 	  case EISCONN:			/* Socket already connected */
119458542Seric #endif
119558542Seric #ifdef EINPROGRESS
119658542Seric 	  case EINPROGRESS:		/* Operation now in progress */
119758542Seric #endif
119858542Seric #ifdef EALREADY
119958542Seric 	  case EALREADY:		/* Operation already in progress */
120058542Seric #endif
120158542Seric #ifdef EADDRINUSE
120258542Seric 	  case EADDRINUSE:		/* Address already in use */
120358542Seric #endif
120458542Seric #ifdef EADDRNOTAVAIL
120558542Seric 	  case EADDRNOTAVAIL:		/* Can't assign requested address */
120658542Seric #endif
120758542Seric #ifdef ENOSR
120858542Seric 	  case ENOSR:			/* Out of streams resources */
120958542Seric #endif
121058542Seric 		return TRUE;
121158542Seric 	}
121258542Seric 
121358542Seric 	/* nope, must be permanent */
121458542Seric 	return FALSE;
121558542Seric }
121658689Seric /*
121758689Seric **  LOCKFILE -- lock a file using flock or (shudder) lockf
121858689Seric **
121958689Seric **	Parameters:
122058689Seric **		fd -- the file descriptor of the file.
122158689Seric **		filename -- the file name (for error messages).
122258689Seric **		type -- type of the lock.  Bits can be:
122358689Seric **			LOCK_EX -- exclusive lock.
122458689Seric **			LOCK_NB -- non-blocking.
122558689Seric **
122658689Seric **	Returns:
122758689Seric **		TRUE if the lock was acquired.
122858689Seric **		FALSE otherwise.
122958689Seric */
123058689Seric 
123158689Seric bool
123258689Seric lockfile(fd, filename, type)
123358689Seric 	int fd;
123458689Seric 	char *filename;
123558689Seric 	int type;
123658689Seric {
123758689Seric # ifdef LOCKF
123858689Seric 	int action;
123958689Seric 	struct flock lfd;
124058689Seric 
124159447Seric 	if (bitset(LOCK_UN, type))
124259447Seric 		lfd.l_type = F_UNLCK;
124359447Seric 	else if (bitset(LOCK_EX, type))
124458689Seric 		lfd.l_type = F_WRLCK;
124558689Seric 	else
124658689Seric 		lfd.l_type = F_RDLCK;
124758689Seric 
124858689Seric 	if (bitset(LOCK_NB, type))
124958689Seric 		action = F_SETLK;
125058689Seric 	else
125158689Seric 		action = F_SETLKW;
125258689Seric 
125358689Seric 	lfd.l_whence = lfd.l_start = lfd.l_len = 0;
125458689Seric 
125558689Seric 	if (fcntl(fd, action, &lfd) >= 0)
125658689Seric 		return TRUE;
125758689Seric 
125858689Seric 	if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN))
125959447Seric 		syserr("cannot lockf(%s, %o)", filename, type);
126058689Seric # else
126158689Seric 	if (flock(fd, type) >= 0)
126258689Seric 		return TRUE;
126358689Seric 
126458689Seric 	if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK)
126559447Seric 		syserr("cannot flock(%s, %o)", filename, type);
126658689Seric # endif
126758689Seric 	return FALSE;
126858689Seric }
1269