xref: /csrg-svn/usr.sbin/sendmail/src/conf.c (revision 33728)
122698Sdist /*
2*33728Sbostic  * Copyright (c) 1988 Regents of the University of California.
3*33728Sbostic  * All rights reserved.
4*33728Sbostic  *
5*33728Sbostic  * Redistribution and use in source and binary forms are permitted
6*33728Sbostic  * provided that this notice is preserved and that due credit is given
7*33728Sbostic  * to the University of California at Berkeley. The name of the University
8*33728Sbostic  * may not be used to endorse or promote products derived from this
9*33728Sbostic  * software without specific prior written permission. This software
10*33728Sbostic  * is provided ``as is'' without express or implied warranty.
11*33728Sbostic  *
12*33728Sbostic  *  Sendmail
13*33728Sbostic  *  Copyright (c) 1983  Eric P. Allman
14*33728Sbostic  *  Berkeley, California
15*33728Sbostic  */
1622698Sdist 
1722698Sdist #ifndef lint
18*33728Sbostic static char sccsid[] = "@(#)conf.c	5.15 (Berkeley) 03/13/88";
19*33728Sbostic #endif /* not lint */
2022698Sdist 
21294Seric # include <pwd.h>
2214881Seric # include <sys/ioctl.h>
2324943Seric # ifdef sun
2424943Seric # include <sys/param.h>
2524943Seric # endif sun
263309Seric # include "sendmail.h"
27404Seric 
28294Seric /*
293309Seric **  CONF.C -- Sendmail Configuration Tables.
30294Seric **
31294Seric **	Defines the configuration of this installation.
32294Seric **
331388Seric **	Compilation Flags:
341388Seric **		V6 -- running on a version 6 system.  This determines
351388Seric **			whether to define certain routines between
361388Seric **			the two systems.  If you are running a funny
371388Seric **			system, e.g., V6 with long tty names, this
381388Seric **			should be checked carefully.
3914872Seric **		VMUNIX -- running on a Berkeley UNIX system.
40294Seric **
411388Seric **	Configuration Variables:
422897Seric **		HdrInfo -- a table describing well-known header fields.
432897Seric **			Each entry has the field name and some flags,
444147Seric **			which are described in sendmail.h.
454093Seric **
464093Seric **	Notes:
474093Seric **		I have tried to put almost all the reasonable
484093Seric **		configuration information into the configuration
494093Seric **		file read at runtime.  My intent is that anything
504093Seric **		here is a function of the version of UNIX you
514093Seric **		are running, or is really static -- for example
524093Seric **		the headers are a superset of widely used
534093Seric **		protocols.  If you find yourself playing with
544093Seric **		this file too much, you may be making a mistake!
55294Seric */
56294Seric 
57294Seric 
58294Seric 
59294Seric 
604437Seric /*
612897Seric **  Header info table
623057Seric **	Final (null) entry contains the flags used for any other field.
634147Seric **
644147Seric **	Not all of these are actually handled specially by sendmail
654147Seric **	at this time.  They are included as placeholders, to let
664147Seric **	you know that "someday" I intend to have sendmail do
674147Seric **	something with them.
682897Seric */
692897Seric 
702897Seric struct hdrinfo	HdrInfo[] =
712897Seric {
728060Seric 		/* originator fields, most to least significant  */
7311417Seric 	"resent-sender",	H_FROM|H_RESENT,
7411417Seric 	"resent-from",		H_FROM|H_RESENT,
7525686Seric 	"resent-reply-to",	H_FROM|H_RESENT,
769055Seric 	"sender",		H_FROM,
779055Seric 	"from",			H_FROM,
7825686Seric 	"reply-to",		H_FROM,
799055Seric 	"full-name",		H_ACHECK,
809055Seric 	"return-receipt-to",	H_FROM,
819055Seric 	"errors-to",		H_FROM,
828060Seric 		/* destination fields */
839055Seric 	"to",			H_RCPT,
8411417Seric 	"resent-to",		H_RCPT|H_RESENT,
859055Seric 	"cc",			H_RCPT,
8611417Seric 	"resent-cc",		H_RCPT|H_RESENT,
879055Seric 	"bcc",			H_RCPT|H_ACHECK,
8811417Seric 	"resent-bcc",		H_RCPT|H_ACHECK|H_RESENT,
898060Seric 		/* message identification and control */
9011417Seric 	"message-id",		0,
9111417Seric 	"resent-message-id",	H_RESENT,
929055Seric 	"message",		H_EOH,
939055Seric 	"text",			H_EOH,
9411417Seric 		/* date fields */
9511417Seric 	"date",			0,
9611417Seric 	"resent-date",		H_RESENT,
978060Seric 		/* trace fields */
989055Seric 	"received",		H_TRACE|H_FORCE,
999055Seric 	"via",			H_TRACE|H_FORCE,
1009055Seric 	"mail-from",		H_TRACE|H_FORCE,
1018060Seric 
1029055Seric 	NULL,			0,
1032897Seric };
1044166Seric 
1054166Seric 
1064166Seric /*
1074166Seric **  ARPANET error message numbers.
1084166Seric */
1094166Seric 
1107956Seric char	Arpa_Info[] =		"050";	/* arbitrary info */
1117956Seric char	Arpa_TSyserr[] =	"451";	/* some (transient) system error */
1127956Seric char	Arpa_PSyserr[] =	"554";	/* some (permanent) system error */
1137956Seric char	Arpa_Usrerr[] =		"554";	/* some (fatal) user error */
1144282Seric 
1154282Seric 
1164282Seric 
1174282Seric /*
1184282Seric **  Location of system files/databases/etc.
1194282Seric */
1204282Seric 
1214282Seric char	*ConfFile =	"/usr/lib/sendmail.cf";	/* runtime configuration */
1229064Seric char	*FreezeFile =	"/usr/lib/sendmail.fc";	/* frozen version of above */
1239039Seric 
1249064Seric 
1259064Seric 
1269039Seric /*
12724943Seric **  Miscellaneous stuff.
1289039Seric */
1299039Seric 
13024943Seric int	DtableSize =	50;		/* max open files; reset in 4.2bsd */
13124943Seric /*
13224943Seric **  SETDEFAULTS -- set default values
13324943Seric **
13424943Seric **	Because of the way freezing is done, these must be initialized
13524943Seric **	using direct code.
13624943Seric **
13724943Seric **	Parameters:
13824943Seric **		none.
13924943Seric **
14024943Seric **	Returns:
14124943Seric **		none.
14224943Seric **
14324943Seric **	Side Effects:
14424943Seric **		Initializes a bunch of global variables to their
14524943Seric **		default values.
14624943Seric */
14724943Seric 
14824943Seric setdefaults()
14924943Seric {
15024943Seric 	QueueLA = 8;
15124943Seric 	QueueFactor = 10000;
15224943Seric 	RefuseLA = 12;
15324943Seric 	SpaceSub = ' ';
15424981Seric 	WkRecipFact = 1000;
15524981Seric 	WkClassFact = 1800;
15625812Seric 	WkTimeFact = 9000;
15724981Seric 	FileMode = 0644;
15824981Seric 	DefUid = 1;
15924981Seric 	DefGid = 1;
16024943Seric }
161294Seric 
162294Seric # ifdef V6
163294Seric /*
1644190Seric **  TTYNAME -- return name of terminal.
165294Seric **
166294Seric **	Parameters:
1674190Seric **		fd -- file descriptor to check.
168294Seric **
169294Seric **	Returns:
1704190Seric **		pointer to full path of tty.
1714190Seric **		NULL if no tty.
172294Seric **
173294Seric **	Side Effects:
174294Seric **		none.
175294Seric */
176294Seric 
177294Seric char *
1784190Seric ttyname(fd)
1794190Seric 	int fd;
180294Seric {
1814190Seric 	register char tn;
182294Seric 	static char pathn[] = "/dev/ttyx";
183294Seric 
184294Seric 	/* compute the pathname of the controlling tty */
1854190Seric 	if ((tn = ttyn(fd)) == NULL)
186294Seric 	{
187294Seric 		errno = 0;
188294Seric 		return (NULL);
189294Seric 	}
1904190Seric 	pathn[8] = tn;
191294Seric 	return (pathn);
192294Seric }
193294Seric /*
194294Seric **  FDOPEN -- Open a stdio file given an open file descriptor.
195294Seric **
196294Seric **	This is included here because it is standard in v7, but we
197294Seric **	need it in v6.
198294Seric **
199294Seric **	Algorithm:
200294Seric **		Open /dev/null to create a descriptor.
201294Seric **		Close that descriptor.
202294Seric **		Copy the existing fd into the descriptor.
203294Seric **
204294Seric **	Parameters:
205294Seric **		fd -- the open file descriptor.
206294Seric **		type -- "r", "w", or whatever.
207294Seric **
208294Seric **	Returns:
209294Seric **		The file descriptor it creates.
210294Seric **
211294Seric **	Side Effects:
212294Seric **		none
213294Seric **
214294Seric **	Called By:
215294Seric **		deliver
216294Seric **
217294Seric **	Notes:
218294Seric **		The mode of fd must match "type".
219294Seric */
220294Seric 
221294Seric FILE *
222294Seric fdopen(fd, type)
223294Seric 	int fd;
224294Seric 	char *type;
225294Seric {
226294Seric 	register FILE *f;
227294Seric 
228294Seric 	f = fopen("/dev/null", type);
2294081Seric 	(void) close(fileno(f));
230294Seric 	fileno(f) = fd;
231294Seric 	return (f);
232294Seric }
233294Seric /*
234294Seric **  INDEX -- Return pointer to character in string
235294Seric **
236294Seric **	For V7 compatibility.
237294Seric **
238294Seric **	Parameters:
239294Seric **		s -- a string to scan.
240294Seric **		c -- a character to look for.
241294Seric **
242294Seric **	Returns:
243294Seric **		If c is in s, returns the address of the first
244294Seric **			instance of c in s.
245294Seric **		NULL if c is not in s.
246294Seric **
247294Seric **	Side Effects:
248294Seric **		none.
249294Seric */
250294Seric 
2514437Seric char *
252294Seric index(s, c)
253294Seric 	register char *s;
254294Seric 	register char c;
255294Seric {
256294Seric 	while (*s != '\0')
257294Seric 	{
258294Seric 		if (*s++ == c)
259294Seric 			return (--s);
260294Seric 	}
261294Seric 	return (NULL);
262294Seric }
2634326Seric /*
2644326Seric **  UMASK -- fake the umask system call.
2654326Seric **
2664326Seric **	Since V6 always acts like the umask is zero, we will just
2674326Seric **	assume the same thing.
2684326Seric */
2694326Seric 
2704326Seric /*ARGSUSED*/
2714326Seric umask(nmask)
2724326Seric {
2734326Seric 	return (0);
2744326Seric }
2754326Seric 
2764326Seric 
2774326Seric /*
2784326Seric **  GETRUID -- get real user id.
2794326Seric */
2804326Seric 
2814326Seric getruid()
2824326Seric {
2834326Seric 	return (getuid() & 0377);
2844326Seric }
2854326Seric 
2864326Seric 
2874326Seric /*
2884326Seric **  GETRGID -- get real group id.
2894326Seric */
2904326Seric 
2914326Seric getrgid()
2924326Seric {
2934326Seric 	return (getgid() & 0377);
2944326Seric }
2954326Seric 
2964326Seric 
2974326Seric /*
2984326Seric **  GETEUID -- get effective user id.
2994326Seric */
3004326Seric 
3014326Seric geteuid()
3024326Seric {
3034326Seric 	return ((getuid() >> 8) & 0377);
3044326Seric }
3054326Seric 
3064326Seric 
3074326Seric /*
3084326Seric **  GETEGID -- get effective group id.
3094326Seric */
3104326Seric 
3114326Seric getegid()
3124326Seric {
3134326Seric 	return ((getgid() >> 8) & 0377);
3144326Seric }
3154326Seric 
316294Seric # endif V6
3174326Seric 
3184326Seric # ifndef V6
3194326Seric 
3204326Seric /*
3214326Seric **  GETRUID -- get real user id (V7)
3224326Seric */
3234326Seric 
3244326Seric getruid()
3254326Seric {
3269274Seric 	if (OpMode == MD_DAEMON)
3274536Seric 		return (RealUid);
3284536Seric 	else
3294536Seric 		return (getuid());
3304326Seric }
3314326Seric 
3324326Seric 
3334326Seric /*
3344326Seric **  GETRGID -- get real group id (V7).
3354326Seric */
3364326Seric 
3374326Seric getrgid()
3384326Seric {
3399274Seric 	if (OpMode == MD_DAEMON)
3404536Seric 		return (RealGid);
3414536Seric 	else
3424536Seric 		return (getgid());
3434326Seric }
3444326Seric 
3454326Seric # endif V6
3464190Seric /*
3479369Seric **  USERNAME -- return the user id of the logged in user.
3489369Seric **
3499369Seric **	Parameters:
3509369Seric **		none.
3519369Seric **
3529369Seric **	Returns:
3539369Seric **		The login name of the logged in user.
3549369Seric **
3559369Seric **	Side Effects:
3569369Seric **		none.
3579369Seric **
3589369Seric **	Notes:
3599369Seric **		The return value is statically allocated.
3609369Seric */
3619369Seric 
3629369Seric char *
3639369Seric username()
3649369Seric {
36517469Seric 	static char *myname = NULL;
3669369Seric 	extern char *getlogin();
36719904Smiriam 	register struct passwd *pw;
36819904Smiriam 	extern struct passwd *getpwuid();
3699369Seric 
37017469Seric 	/* cache the result */
37117469Seric 	if (myname == NULL)
37217469Seric 	{
37317469Seric 		myname = getlogin();
37417469Seric 		if (myname == NULL || myname[0] == '\0')
37517469Seric 		{
37617469Seric 
37717469Seric 			pw = getpwuid(getruid());
37817469Seric 			if (pw != NULL)
37917469Seric 				myname = pw->pw_name;
38017469Seric 		}
38119904Smiriam 		else
38219904Smiriam 		{
38319873Smiriam 
38419873Smiriam 			pw = getpwnam(myname);
38519904Smiriam 			if(getuid() != pw->pw_uid)
38619904Smiriam 			{
38719873Smiriam 				pw = getpwuid(getuid());
38824945Seric 				if (pw != NULL)
38924945Seric 					myname = pw->pw_name;
39019873Smiriam 			}
39119873Smiriam 		}
39217469Seric 		if (myname == NULL || myname[0] == '\0')
39317469Seric 		{
39417469Seric 			syserr("Who are you?");
39517469Seric 			myname = "postmaster";
39617469Seric 		}
39717469Seric 	}
39817469Seric 
39917469Seric 	return (myname);
4009369Seric }
4019369Seric /*
4024190Seric **  TTYPATH -- Get the path of the user's tty
403294Seric **
404294Seric **	Returns the pathname of the user's tty.  Returns NULL if
405294Seric **	the user is not logged in or if s/he has write permission
406294Seric **	denied.
407294Seric **
408294Seric **	Parameters:
409294Seric **		none
410294Seric **
411294Seric **	Returns:
412294Seric **		pathname of the user's tty.
413294Seric **		NULL if not logged in or write permission denied.
414294Seric **
415294Seric **	Side Effects:
416294Seric **		none.
417294Seric **
418294Seric **	WARNING:
419294Seric **		Return value is in a local buffer.
420294Seric **
421294Seric **	Called By:
422294Seric **		savemail
423294Seric */
424294Seric 
425294Seric # include <sys/stat.h>
426294Seric 
427294Seric char *
428294Seric ttypath()
429294Seric {
430294Seric 	struct stat stbuf;
431294Seric 	register char *pathn;
432294Seric 	extern char *ttyname();
4334081Seric 	extern char *getlogin();
434294Seric 
435294Seric 	/* compute the pathname of the controlling tty */
4369369Seric 	if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
4379369Seric 	    (pathn = ttyname(0)) == NULL)
438294Seric 	{
439294Seric 		errno = 0;
440294Seric 		return (NULL);
441294Seric 	}
442294Seric 
443294Seric 	/* see if we have write permission */
4442967Seric 	if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
445294Seric 	{
446294Seric 		errno = 0;
447294Seric 		return (NULL);
448294Seric 	}
449294Seric 
450294Seric 	/* see if the user is logged in */
451294Seric 	if (getlogin() == NULL)
452294Seric 		return (NULL);
453294Seric 
454294Seric 	/* looks good */
455294Seric 	return (pathn);
456294Seric }
4572967Seric /*
4582967Seric **  CHECKCOMPAT -- check for From and To person compatible.
4592967Seric **
4602967Seric **	This routine can be supplied on a per-installation basis
4612967Seric **	to determine whether a person is allowed to send a message.
4622967Seric **	This allows restriction of certain types of internet
4632967Seric **	forwarding or registration of users.
4642967Seric **
4652967Seric **	If the hosts are found to be incompatible, an error
4662967Seric **	message should be given using "usrerr" and FALSE should
4672967Seric **	be returned.
4682967Seric **
4694288Seric **	'NoReturn' can be set to suppress the return-to-sender
4704288Seric **	function; this should be done on huge messages.
4714288Seric **
4722967Seric **	Parameters:
4732967Seric **		to -- the person being sent to.
4742967Seric **
4752967Seric **	Returns:
4762967Seric **		TRUE -- ok to send.
4772967Seric **		FALSE -- not ok.
4782967Seric **
4792967Seric **	Side Effects:
4802967Seric **		none (unless you include the usrerr stuff)
4812967Seric */
4822967Seric 
4832967Seric bool
4842967Seric checkcompat(to)
4852967Seric 	register ADDRESS *to;
4862967Seric {
48712133Seric # ifdef lint
48812133Seric 	if (to == NULL)
48912133Seric 		to++;
49012133Seric # endif lint
49110698Seric # ifdef EXAMPLE_CODE
49210698Seric 	/* this code is intended as an example only */
4934437Seric 	register STAB *s;
4944437Seric 
4954437Seric 	s = stab("arpa", ST_MAILER, ST_FIND);
4969369Seric 	if (s != NULL && CurEnv->e_from.q_mailer != LocalMailer &&
4979369Seric 	    to->q_mailer == s->s_mailer)
4984437Seric 	{
4994437Seric 		usrerr("No ARPA mail through this machine: see your system administration");
50010698Seric 		/* NoReturn = TRUE; to supress return copy */
5014437Seric 		return (FALSE);
5024437Seric 	}
50310698Seric # endif EXAMPLE_CODE
5042967Seric 	return (TRUE);
5052967Seric }
5069369Seric /*
5079369Seric **  HOLDSIGS -- arrange to hold all signals
5089369Seric **
5099369Seric **	Parameters:
5109369Seric **		none.
5119369Seric **
5129369Seric **	Returns:
5139369Seric **		none.
5149369Seric **
5159369Seric **	Side Effects:
5169369Seric **		Arranges that signals are held.
5179369Seric */
5189369Seric 
5199369Seric holdsigs()
5209369Seric {
5219369Seric }
5229369Seric /*
5239369Seric **  RLSESIGS -- arrange to release all signals
5249369Seric **
5259369Seric **	This undoes the effect of holdsigs.
5269369Seric **
5279369Seric **	Parameters:
5289369Seric **		none.
5299369Seric **
5309369Seric **	Returns:
5319369Seric **		none.
5329369Seric **
5339369Seric **	Side Effects:
5349369Seric **		Arranges that signals are released.
5359369Seric */
5369369Seric 
5379369Seric rlsesigs()
5389369Seric {
5399369Seric }
54014872Seric /*
54114872Seric **  GETLA -- get the current load average
54214872Seric **
54314881Seric **	This code stolen from la.c.
54414881Seric **
54514872Seric **	Parameters:
54614872Seric **		none.
54714872Seric **
54814872Seric **	Returns:
54914872Seric **		The current load average as an integer.
55014872Seric **
55114872Seric **	Side Effects:
55214872Seric **		none.
55314872Seric */
55414872Seric 
55514872Seric #ifdef VMUNIX
55614872Seric 
55714872Seric #include <nlist.h>
55814872Seric 
55914872Seric struct	nlist Nl[] =
56014872Seric {
56114872Seric 	{ "_avenrun" },
56214872Seric #define	X_AVENRUN	0
56314872Seric 	{ 0 },
56414872Seric };
56514872Seric 
56614872Seric getla()
56714872Seric {
56814872Seric 	static int kmem = -1;
56924943Seric # ifdef sun
57024943Seric 	long avenrun[3];
57124943Seric # else
57214872Seric 	double avenrun[3];
57324943Seric # endif
57425615Seric 	extern off_t lseek();
57514872Seric 
57614872Seric 	if (kmem < 0)
57714872Seric 	{
57824945Seric 		kmem = open("/dev/kmem", 0, 0);
57914872Seric 		if (kmem < 0)
58014872Seric 			return (-1);
58123118Seric 		(void) ioctl(kmem, (int) FIOCLEX, (char *) 0);
58214872Seric 		nlist("/vmunix", Nl);
58314872Seric 		if (Nl[0].n_type == 0)
58414872Seric 			return (-1);
58514872Seric 	}
58624945Seric 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
58723118Seric 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
58819967Seric 	{
58919967Seric 		/* thank you Ian */
59019967Seric 		return (-1);
59119967Seric 	}
59224943Seric # ifdef sun
59324943Seric 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
59424943Seric # else
59514872Seric 	return ((int) (avenrun[0] + 0.5));
59624943Seric # endif
59714872Seric }
59814872Seric 
59914872Seric #else VMUNIX
60014872Seric 
60114872Seric getla()
60214872Seric {
60314872Seric 	return (0);
60414872Seric }
60514872Seric 
60614872Seric #endif VMUNIX
60724943Seric /*
60824943Seric **  SHOULDQUEUE -- should this message be queued or sent?
60924943Seric **
61024943Seric **	Compares the message cost to the load average to decide.
61124943Seric **
61224943Seric **	Parameters:
61324943Seric **		pri -- the priority of the message in question.
61424943Seric **
61524943Seric **	Returns:
61624943Seric **		TRUE -- if this message should be queued up for the
61724943Seric **			time being.
61824943Seric **		FALSE -- if the load is low enough to send this message.
61924943Seric **
62024943Seric **	Side Effects:
62124943Seric **		none.
62224943Seric */
62324943Seric 
62424943Seric bool
62524943Seric shouldqueue(pri)
62624943Seric 	long pri;
62724943Seric {
62824943Seric 	int la;
62924943Seric 
63024943Seric 	la = getla();
63124943Seric 	if (la < QueueLA)
63224943Seric 		return (FALSE);
63324943Seric 	return (pri > (QueueFactor / (la - QueueLA + 1)));
63424943Seric }
63524943Seric /*
63624943Seric **  SETPROCTITLE -- set process title for ps
63724943Seric **
63824943Seric **	Parameters:
63924943Seric **		fmt -- a printf style format string.
64024943Seric **		a, b, c -- possible parameters to fmt.
64124943Seric **
64224943Seric **	Returns:
64324943Seric **		none.
64424943Seric **
64524943Seric **	Side Effects:
64624943Seric **		Clobbers argv of our main procedure so ps(1) will
64724943Seric **		display the title.
64824943Seric */
64924943Seric 
65024943Seric /*VARARGS1*/
65124943Seric setproctitle(fmt, a, b, c)
65224943Seric 	char *fmt;
65324943Seric {
65424943Seric # ifdef SETPROCTITLE
65524943Seric 	register char *p;
65625049Seric 	register int i;
65724943Seric 	extern char **Argv;
65824943Seric 	extern char *LastArgv;
65925049Seric 	char buf[MAXLINE];
66024943Seric 
66125049Seric 	(void) sprintf(buf, fmt, a, b, c);
66224943Seric 
66324943Seric 	/* make ps print "(sendmail)" */
66425049Seric 	p = Argv[0];
66524943Seric 	*p++ = '-';
66624943Seric 
66725049Seric 	i = strlen(buf);
66825049Seric 	if (i > LastArgv - p - 2)
66925049Seric 	{
67025049Seric 		i = LastArgv - p - 2;
67125049Seric 		buf[i] = '\0';
67225049Seric 	}
67325049Seric 	(void) strcpy(p, buf);
67425049Seric 	p += i;
67524943Seric 	while (p < LastArgv)
67624943Seric 		*p++ = ' ';
67724943Seric # endif SETPROCTITLE
67824943Seric }
67925698Seric /*
68025698Seric **  REAPCHILD -- pick up the body of my child, lest it become a zombie
68125698Seric **
68225698Seric **	Parameters:
68325698Seric **		none.
68425698Seric **
68525698Seric **	Returns:
68625698Seric **		none.
68725698Seric **
68825698Seric **	Side Effects:
68925698Seric **		Picks up extant zombies.
69025698Seric */
69125698Seric 
69225698Seric # ifdef VMUNIX
69325698Seric # include <sys/wait.h>
69425698Seric # endif VMUNIX
69525698Seric 
69625698Seric reapchild()
69725698Seric {
69825698Seric # ifdef WNOHANG
69925698Seric 	union wait status;
70025698Seric 
70125698Seric 	while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
70225698Seric 		continue;
70325698Seric # else WNOHANG
70425698Seric 	auto int status;
70525698Seric 
70625698Seric 	while (wait(&status) > 0)
70725698Seric 		continue;
70825698Seric # endif WNOHANG
70925698Seric }
710