xref: /csrg-svn/usr.sbin/sendmail/src/conf.c (revision 58151)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)conf.c	6.25 (Berkeley) 02/23/93";
11 #endif /* not lint */
12 
13 # include <sys/ioctl.h>
14 # include <sys/param.h>
15 # include <pwd.h>
16 # include "sendmail.h"
17 # include "pathnames.h"
18 
19 /*
20 **  CONF.C -- Sendmail Configuration Tables.
21 **
22 **	Defines the configuration of this installation.
23 **
24 **	Configuration Variables:
25 **		HdrInfo -- a table describing well-known header fields.
26 **			Each entry has the field name and some flags,
27 **			which are described in sendmail.h.
28 **
29 **	Notes:
30 **		I have tried to put almost all the reasonable
31 **		configuration information into the configuration
32 **		file read at runtime.  My intent is that anything
33 **		here is a function of the version of UNIX you
34 **		are running, or is really static -- for example
35 **		the headers are a superset of widely used
36 **		protocols.  If you find yourself playing with
37 **		this file too much, you may be making a mistake!
38 */
39 
40 
41 
42 
43 /*
44 **  Header info table
45 **	Final (null) entry contains the flags used for any other field.
46 **
47 **	Not all of these are actually handled specially by sendmail
48 **	at this time.  They are included as placeholders, to let
49 **	you know that "someday" I intend to have sendmail do
50 **	something with them.
51 */
52 
53 struct hdrinfo	HdrInfo[] =
54 {
55 		/* originator fields, most to least significant  */
56 	"resent-sender",	H_FROM|H_RESENT,
57 	"resent-from",		H_FROM|H_RESENT,
58 	"resent-reply-to",	H_FROM|H_RESENT,
59 	"sender",		H_FROM,
60 	"from",			H_FROM,
61 	"reply-to",		H_FROM,
62 	"full-name",		H_ACHECK,
63 	"return-receipt-to",	H_FROM /* |H_RECEIPTTO */,
64 	"errors-to",		H_FROM|H_ERRORSTO,
65 		/* destination fields */
66 	"to",			H_RCPT,
67 	"resent-to",		H_RCPT|H_RESENT,
68 	"cc",			H_RCPT,
69 	"resent-cc",		H_RCPT|H_RESENT,
70 	"bcc",			H_RCPT|H_ACHECK,
71 	"resent-bcc",		H_RCPT|H_ACHECK|H_RESENT,
72 	"apparently-to",	H_RCPT,
73 		/* message identification and control */
74 	"message-id",		0,
75 	"resent-message-id",	H_RESENT,
76 	"message",		H_EOH,
77 	"text",			H_EOH,
78 		/* date fields */
79 	"date",			0,
80 	"resent-date",		H_RESENT,
81 		/* trace fields */
82 	"received",		H_TRACE|H_FORCE,
83 	"via",			H_TRACE|H_FORCE,
84 	"mail-from",		H_TRACE|H_FORCE,
85 
86 	NULL,			0,
87 };
88 
89 
90 
91 /*
92 **  Location of system files/databases/etc.
93 */
94 
95 char	*ConfFile =	_PATH_SENDMAILCF;	/* runtime configuration */
96 char	*FreezeFile =	_PATH_SENDMAILFC;	/* frozen version of above */
97 char	*PidFile =	_PATH_SENDMAILPID;	/* stores daemon proc id */
98 
99 
100 
101 /*
102 **  Privacy values
103 */
104 
105 struct prival PrivacyValues[] =
106 {
107 	"public",		PRIV_PUBLIC,
108 	"needmailhelo",		PRIV_NEEDMAILHELO,
109 	"needexpnhelo",		PRIV_NEEDEXPNHELO,
110 	"needvrfyhelo",		PRIV_NEEDVRFYHELO,
111 	"noexpn",		PRIV_NOEXPN,
112 	"novrfy",		PRIV_NOVRFY,
113 	"goaway",		PRIV_GOAWAY,
114 	NULL,			PRIV_PUBLIC,
115 };
116 
117 
118 
119 /*
120 **  Miscellaneous stuff.
121 */
122 
123 int	DtableSize =	50;		/* max open files; reset in 4.2bsd */
124 /*
125 **  SETDEFAULTS -- set default values
126 **
127 **	Because of the way freezing is done, these must be initialized
128 **	using direct code.
129 **
130 **	Parameters:
131 **		none.
132 **
133 **	Returns:
134 **		none.
135 **
136 **	Side Effects:
137 **		Initializes a bunch of global variables to their
138 **		default values.
139 */
140 
141 setdefaults()
142 {
143 	SpaceSub = ' ';				/* option B */
144 	QueueLA = 8;				/* option x */
145 	RefuseLA = 12;				/* option X */
146 	WkRecipFact = 30000L;			/* option y */
147 	WkClassFact = 1800L;			/* option z */
148 	WkTimeFact = 90000L;			/* option Z */
149 	QueueFactor = WkRecipFact * 20;		/* option q */
150 	FileMode = (getuid() != geteuid()) ? 0644 : 0600;
151 						/* option F */
152 	DefUid = 1;				/* option u */
153 	DefGid = 1;				/* option g */
154 	CheckpointInterval = 10;		/* option C */
155 	MaxHopCount = 25;			/* option h */
156 	SendMode = SM_FORK;			/* option d */
157 	ErrorMode = EM_PRINT;			/* option e */
158 	EightBit = FALSE;			/* option 8 */
159 	MaxMciCache = 1;			/* option k */
160 	MciCacheTimeout = 300;			/* option K */
161 	LogLevel = 9;				/* option L */
162 	settimeouts(NULL);			/* option r */
163 	TimeOut = 5 * 24 * 60 * 60;		/* option T */
164 	setdefuser();
165 	setupmaps();
166 	setupmailers();
167 }
168 
169 
170 /*
171 **  SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
172 */
173 
174 setdefuser()
175 {
176 	struct passwd *defpwent;
177 	static char defuserbuf[40];
178 
179 	DefUser = defuserbuf;
180 	if ((defpwent = getpwuid(DefUid)) != NULL)
181 		strcpy(defuserbuf, defpwent->pw_name);
182 	else
183 		strcpy(defuserbuf, "nobody");
184 }
185 /*
186 **  SETUPMAPS -- set up map classes
187 **
188 **	Since these are compiled in, they cannot be in the config file.
189 **
190 */
191 
192 setupmaps()
193 {
194 	register STAB *s;
195 	extern bool host_map_init();
196 	extern char *maphostname();
197 
198 	/* set up host name lookup map */
199 	s = stab("host", ST_MAPCLASS, ST_ENTER);
200 	s->s_mapclass.map_init = host_map_init;
201 	s->s_mapclass.map_lookup = maphostname;
202 
203 	/*
204 	**  Set up other map classes.
205 	*/
206 
207 # ifdef DBM_MAP
208 	/* dbm file access */
209 	{
210 		extern bool dbm_map_init();
211 		extern char *dbm_map_lookup();
212 
213 		s = stab("dbm", ST_MAPCLASS, ST_ENTER);
214 		s->s_mapclass.map_init = dbm_map_init;
215 		s->s_mapclass.map_lookup = dbm_map_lookup;
216 	}
217 # endif
218 
219 # ifdef BTREE_MAP
220 	/* new database file access -- btree files */
221 	{
222 		extern bool bt_map_init();
223 		extern char *db_map_lookup();
224 
225 		s = stab("btree", ST_MAPCLASS, ST_ENTER);
226 		s->s_mapclass.map_init = bt_map_init;
227 		s->s_mapclass.map_lookup = db_map_lookup;
228 	}
229 # endif
230 
231 # ifdef HASH_MAP
232 	/* new database file access -- hash files */
233 	{
234 		extern bool hash_map_init();
235 		extern char *db_map_lookup();
236 
237 		s = stab("hash", ST_MAPCLASS, ST_ENTER);
238 		s->s_mapclass.map_init = hash_map_init;
239 		s->s_mapclass.map_lookup = db_map_lookup;
240 	}
241 # endif
242 
243 # ifdef NIS_MAP
244 	/* NIS map access */
245 	{
246 		extern bool nis_map_init();
247 		extern char *nis_map_lookup();
248 
249 		s = stab("nis", ST_MAPCLASS, ST_ENTER);
250 		s->s_mapclass.map_init = nis_map_init;
251 		s->s_mapclass.map_lookup = nis_map_lookup;
252 	}
253 # endif
254 
255 # ifdef USERDB_MAP
256 	/* user database */
257 	{
258 		extern bool udb_map_init();
259 		extern char *udb_map_lookup();
260 
261 		s = stab("udb", ST_MAPCLASS, ST_ENTER);
262 		s->s_mapclass.map_init = udb_map_init;
263 		s->s_mapclass.map_lookup = udb_map_lookup;
264 	}
265 # endif
266 }
267 /*
268 **  HOST_MAP_INIT -- initialize host class structures
269 */
270 
271 bool
272 host_map_init(map, mapname, args)
273 	MAP *map;
274 	char *mapname;
275 	char *args;
276 {
277 	register char *p = args;
278 
279 	for (;;)
280 	{
281 		while (isascii(*p) && isspace(*p))
282 			p++;
283 		if (*p != '-')
284 			break;
285 		switch (*++p)
286 		{
287 		  case 'a':
288 			map->map_app = ++p;
289 			break;
290 		}
291 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
292 			p++;
293 		if (*p != '\0')
294 			*p++ = '\0';
295 	}
296 	if (map->map_app != NULL)
297 		map->map_app = newstr(map->map_app);
298 	return TRUE;
299 }
300 /*
301 **  SETUPMAILERS -- initialize default mailers
302 */
303 
304 setupmailers()
305 {
306 	char buf[100];
307 
308 	strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u");
309 	makemailer(buf);
310 
311 	strcpy(buf, "*file*, P=/dev/null, F=lsDEu, A=FILE");
312 	makemailer(buf);
313 
314 	strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE");
315 	makemailer(buf);
316 }
317 /*
318 **  GETRUID -- get real user id (V7)
319 */
320 
321 getruid()
322 {
323 	if (OpMode == MD_DAEMON)
324 		return (RealUid);
325 	else
326 		return (getuid());
327 }
328 
329 
330 /*
331 **  GETRGID -- get real group id (V7).
332 */
333 
334 getrgid()
335 {
336 	if (OpMode == MD_DAEMON)
337 		return (RealGid);
338 	else
339 		return (getgid());
340 }
341 /*
342 **  USERNAME -- return the user id of the logged in user.
343 **
344 **	Parameters:
345 **		none.
346 **
347 **	Returns:
348 **		The login name of the logged in user.
349 **
350 **	Side Effects:
351 **		none.
352 **
353 **	Notes:
354 **		The return value is statically allocated.
355 */
356 
357 char *
358 username()
359 {
360 	static char *myname = NULL;
361 	extern char *getlogin();
362 	register struct passwd *pw;
363 
364 	/* cache the result */
365 	if (myname == NULL)
366 	{
367 		myname = getlogin();
368 		if (myname == NULL || myname[0] == '\0')
369 		{
370 
371 			pw = getpwuid(getruid());
372 			if (pw != NULL)
373 				myname = newstr(pw->pw_name);
374 		}
375 		else
376 		{
377 
378 			myname = newstr(myname);
379 			if ((pw = getpwnam(myname)) == NULL ||
380 			      getuid() != pw->pw_uid)
381 			{
382 				pw = getpwuid(getuid());
383 				if (pw != NULL)
384 					myname = newstr(pw->pw_name);
385 			}
386 		}
387 		if (myname == NULL || myname[0] == '\0')
388 		{
389 			syserr("554 Who are you?");
390 			myname = "postmaster";
391 		}
392 	}
393 
394 	return (myname);
395 }
396 /*
397 **  TTYPATH -- Get the path of the user's tty
398 **
399 **	Returns the pathname of the user's tty.  Returns NULL if
400 **	the user is not logged in or if s/he has write permission
401 **	denied.
402 **
403 **	Parameters:
404 **		none
405 **
406 **	Returns:
407 **		pathname of the user's tty.
408 **		NULL if not logged in or write permission denied.
409 **
410 **	Side Effects:
411 **		none.
412 **
413 **	WARNING:
414 **		Return value is in a local buffer.
415 **
416 **	Called By:
417 **		savemail
418 */
419 
420 # include <sys/stat.h>
421 
422 char *
423 ttypath()
424 {
425 	struct stat stbuf;
426 	register char *pathn;
427 	extern char *ttyname();
428 	extern char *getlogin();
429 
430 	/* compute the pathname of the controlling tty */
431 	if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
432 	    (pathn = ttyname(0)) == NULL)
433 	{
434 		errno = 0;
435 		return (NULL);
436 	}
437 
438 	/* see if we have write permission */
439 	if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
440 	{
441 		errno = 0;
442 		return (NULL);
443 	}
444 
445 	/* see if the user is logged in */
446 	if (getlogin() == NULL)
447 		return (NULL);
448 
449 	/* looks good */
450 	return (pathn);
451 }
452 /*
453 **  CHECKCOMPAT -- check for From and To person compatible.
454 **
455 **	This routine can be supplied on a per-installation basis
456 **	to determine whether a person is allowed to send a message.
457 **	This allows restriction of certain types of internet
458 **	forwarding or registration of users.
459 **
460 **	If the hosts are found to be incompatible, an error
461 **	message should be given using "usrerr" and 0 should
462 **	be returned.
463 **
464 **	'NoReturn' can be set to suppress the return-to-sender
465 **	function; this should be done on huge messages.
466 **
467 **	Parameters:
468 **		to -- the person being sent to.
469 **
470 **	Returns:
471 **		an exit status
472 **
473 **	Side Effects:
474 **		none (unless you include the usrerr stuff)
475 */
476 
477 checkcompat(to, e)
478 	register ADDRESS *to;
479 	register ENVELOPE *e;
480 {
481 # ifdef lint
482 	if (to == NULL)
483 		to++;
484 # endif lint
485 # ifdef EXAMPLE_CODE
486 	/* this code is intended as an example only */
487 	register STAB *s;
488 
489 	s = stab("arpa", ST_MAILER, ST_FIND);
490 	if (s != NULL && e->e_from.q_mailer != LocalMailer &&
491 	    to->q_mailer == s->s_mailer)
492 	{
493 		usrerr("553 No ARPA mail through this machine: see your system administration");
494 		/* NoReturn = TRUE; to supress return copy */
495 		return (EX_UNAVAILABLE);
496 	}
497 # endif /* EXAMPLE_CODE */
498 	return (EX_OK);
499 }
500 /*
501 **  HOLDSIGS -- arrange to hold all signals
502 **
503 **	Parameters:
504 **		none.
505 **
506 **	Returns:
507 **		none.
508 **
509 **	Side Effects:
510 **		Arranges that signals are held.
511 */
512 
513 holdsigs()
514 {
515 }
516 /*
517 **  RLSESIGS -- arrange to release all signals
518 **
519 **	This undoes the effect of holdsigs.
520 **
521 **	Parameters:
522 **		none.
523 **
524 **	Returns:
525 **		none.
526 **
527 **	Side Effects:
528 **		Arranges that signals are released.
529 */
530 
531 rlsesigs()
532 {
533 }
534 /*
535 **  GETLA -- get the current load average
536 **
537 **	This code stolen from la.c.
538 **
539 **	Parameters:
540 **		none.
541 **
542 **	Returns:
543 **		The current load average as an integer.
544 **
545 **	Side Effects:
546 **		none.
547 */
548 
549 /* try to guess what style of load average we have */
550 #define LA_ZERO		1	/* always return load average as zero */
551 #define LA_INT		2	/* read kmem for avenrun; interpret as int */
552 #define LA_FLOAT	3	/* read kmem for avenrun; interpret as float */
553 #define LA_SUBR		4	/* call getloadavg */
554 
555 #ifndef LA_TYPE
556 #  if defined(sun)
557 #    define LA_TYPE		LA_INT
558 #  endif
559 #  if defined(mips) || defined(__alpha)
560      /* Ultrix or OSF/1 or RISC/os */
561 #    define LA_TYPE		LA_INT
562 #    define LA_AVENRUN		"avenrun"
563 #  endif
564 #  if defined(hpux)
565 #    define LA_TYPE		LA_FLOAT
566 #  endif
567 
568 #  ifndef LA_TYPE
569 #   if defined(SYSTEM5)
570 #    define LA_TYPE		LA_INT
571 #    define LA_AVENRUN		"avenrun"
572 #   else
573 #    if defined(BSD)
574 #     define LA_TYPE		LA_SUBR
575 #    else
576 #     define LA_TYPE		LA_ZERO
577 #    endif
578 #   endif
579 #  endif
580 #endif
581 
582 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT)
583 
584 #include <nlist.h>
585 #include <fcntl.h>
586 
587 #ifndef LA_AVENRUN
588 #define LA_AVENRUN	"_avenrun"
589 #endif
590 
591 /* _PATH_UNIX should be defined in <paths.h> */
592 #ifndef _PATH_UNIX
593 #  if defined(hpux)
594 #    define _PATH_UNIX		"/hp-ux"
595 #  endif
596 #  if defined(mips) && !defined(ultrix)
597      /* powerful RISC/os */
598 #    define _PATH_UNIX		"/unix"
599 #  endif
600 #  if defined(SYSTEM5)
601 #    ifndef _PATH_UNIX
602 #      define _PATH_UNIX	"/unix"
603 #    endif
604 #  endif
605 #  ifndef _PATH_UNIX
606 #    define _PATH_UNIX		"/vmunix"
607 #  endif
608 #endif
609 
610 struct	nlist Nl[] =
611 {
612 	{ LA_AVENRUN },
613 #define	X_AVENRUN	0
614 	{ 0 },
615 };
616 
617 #if defined(unixpc)
618 # define FSHIFT		5
619 #endif
620 
621 #if defined(__alpha)
622 # define FSHIFT		10
623 #endif
624 
625 #if (LA_TYPE == LA_INT) && !defined(FSHIFT)
626 #  define FSHIFT	8
627 #endif
628 #if (LA_TYPE == LA_INT) && !defined(FSCALE)
629 #  define FSCALE	(1 << FSHIFT)
630 #endif
631 
632 getla()
633 {
634 	static int kmem = -1;
635 #if LA_TYPE == LA_INT
636 	long avenrun[3];
637 #else
638 	double avenrun[3];
639 #endif
640 	extern off_t lseek();
641 	extern char *errstring();
642 	extern int errno;
643 
644 	if (kmem < 0)
645 	{
646 		kmem = open("/dev/kmem", 0, 0);
647 		if (kmem < 0)
648 		{
649 			if (tTd(3, 1))
650 				printf("getla: open(/dev/kmem): %s\n",
651 					errstring(errno));
652 			return (-1);
653 		}
654 		(void) fcntl(kmem, F_SETFD, 1);
655 		if (nlist(_PATH_UNIX, Nl) < 0)
656 		{
657 			if (tTd(3, 1))
658 				printf("getla: nlist(%s): %s\n", _PATH_UNIX,
659 					errstring(errno));
660 			return (-1);
661 		}
662 	}
663 	if (tTd(3, 20))
664 		printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value);
665 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
666 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
667 	{
668 		/* thank you Ian */
669 		if (tTd(3, 1))
670 			printf("getla: lseek or read: %s\n", errstring(errno));
671 		return (-1);
672 	}
673 #if LA_TYPE == LA_INT
674 	if (tTd(3, 5))
675 	{
676 		printf("getla: avenrun = %d", avenrun[0]);
677 		if (tTd(3, 15))
678 			printf(", %d, %d", avenrun[1], avenrun[2]);
679 		printf("\n");
680 	}
681 	if (tTd(3, 1))
682 		printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
683 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
684 #else
685 	if (tTd(3, 5))
686 	{
687 		printf("getla: avenrun = %g", avenrun[0]);
688 		if (tTd(3, 15))
689 			printf(", %g, %g", avenrun[1], avenrun[2]);
690 		printf("\n");
691 	}
692 	if (tTd(3, 1))
693 		printf("getla: %d\n", (int) (avenrun[0] +0.5));
694 	return ((int) (avenrun[0] + 0.5));
695 #endif
696 }
697 
698 #else
699 #if LA_TYPE == LA_SUBR
700 
701 getla()
702 {
703 	double avenrun[3];
704 
705 	if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
706 	{
707 		if (tTd(3, 1))
708 			perror("getla: getloadavg failed:");
709 		return (-1);
710 	}
711 	if (tTd(3, 1))
712 		printf("getla: %d\n", (int) (avenrun[0] +0.5));
713 	return ((int) (avenrun[0] + 0.5));
714 }
715 
716 #else
717 
718 getla()
719 {
720 	if (tTd(3, 1))
721 		printf("getla: ZERO\n");
722 	return (0);
723 }
724 
725 #endif
726 #endif
727 /*
728 **  SHOULDQUEUE -- should this message be queued or sent?
729 **
730 **	Compares the message cost to the load average to decide.
731 **
732 **	Parameters:
733 **		pri -- the priority of the message in question.
734 **		ctime -- the message creation time.
735 **
736 **	Returns:
737 **		TRUE -- if this message should be queued up for the
738 **			time being.
739 **		FALSE -- if the load is low enough to send this message.
740 **
741 **	Side Effects:
742 **		none.
743 */
744 
745 bool
746 shouldqueue(pri, ctime)
747 	long pri;
748 	time_t ctime;
749 {
750 	if (CurrentLA < QueueLA)
751 		return (FALSE);
752 	if (CurrentLA >= RefuseLA)
753 		return (TRUE);
754 	return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
755 }
756 /*
757 **  REFUSECONNECTIONS -- decide if connections should be refused
758 **
759 **	Parameters:
760 **		none.
761 **
762 **	Returns:
763 **		TRUE if incoming SMTP connections should be refused
764 **			(for now).
765 **		FALSE if we should accept new work.
766 **
767 **	Side Effects:
768 **		none.
769 */
770 
771 bool
772 refuseconnections()
773 {
774 	/* this is probably too simplistic */
775 	return (CurrentLA >= RefuseLA);
776 }
777 /*
778 **  SETPROCTITLE -- set process title for ps
779 **
780 **	Parameters:
781 **		fmt -- a printf style format string.
782 **		a, b, c -- possible parameters to fmt.
783 **
784 **	Returns:
785 **		none.
786 **
787 **	Side Effects:
788 **		Clobbers argv of our main procedure so ps(1) will
789 **		display the title.
790 */
791 
792 /*VARARGS1*/
793 #ifdef __STDC__
794 setproctitle(char *fmt, ...)
795 #else
796 setproctitle(fmt, va_alist)
797 	char *fmt;
798 	va_dcl
799 #endif
800 {
801 # ifdef SETPROCTITLE
802 	register char *p;
803 	register int i;
804 	char buf[MAXLINE];
805 	VA_LOCAL_DECL
806 	extern char **Argv;
807 	extern char *LastArgv;
808 
809 	p = buf;
810 
811 	/* print sendmail: heading for grep */
812 	(void) strcpy(p, "sendmail: ");
813 	p += strlen(p);
814 
815 	/* print the argument string */
816 	VA_START(fmt);
817 	(void) vsprintf(p, fmt, ap);
818 	VA_END;
819 
820 	i = strlen(buf);
821 	if (i > LastArgv - Argv[0] - 2)
822 	{
823 		i = LastArgv - Argv[0] - 2;
824 		buf[i] = '\0';
825 	}
826 	(void) strcpy(Argv[0], buf);
827 	p = &Argv[0][i];
828 	while (p < LastArgv)
829 		*p++ = ' ';
830 # endif /* SETPROCTITLE */
831 }
832 /*
833 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
834 **
835 **	Parameters:
836 **		none.
837 **
838 **	Returns:
839 **		none.
840 **
841 **	Side Effects:
842 **		Picks up extant zombies.
843 */
844 
845 # include <sys/wait.h>
846 
847 void
848 reapchild()
849 {
850 # ifdef WNOHANG
851 	union wait status;
852 
853 	while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
854 		continue;
855 # else /* WNOHANG */
856 	auto int status;
857 
858 	while (wait((int *)&status) > 0)
859 		continue;
860 # endif /* WNOHANG */
861 # ifdef SYSTEM5
862 	(void) signal(SIGCHLD, reapchild);
863 # endif
864 }
865 /*
866 **  UNSETENV -- remove a variable from the environment
867 **
868 **	Not needed on newer systems.
869 **
870 **	Parameters:
871 **		name -- the string name of the environment variable to be
872 **			deleted from the current environment.
873 **
874 **	Returns:
875 **		none.
876 **
877 **	Globals:
878 **		environ -- a pointer to the current environment.
879 **
880 **	Side Effects:
881 **		Modifies environ.
882 */
883 
884 #ifdef UNSETENV
885 
886 void
887 unsetenv(name)
888 	char *name;
889 {
890 	extern char **environ;
891 	register char **pp;
892 	int len = strlen(name);
893 
894 	for (pp = environ; *pp != NULL; pp++)
895 	{
896 		if (strncmp(name, *pp, len) == 0 &&
897 		    ((*pp)[len] == '=' || (*pp)[len] == '\0'))
898 			break;
899 	}
900 
901 	for (; *pp != NULL; pp++)
902 		*pp = pp[1];
903 }
904 
905 #endif /* UNSETENV */
906 /*
907 **  GETDTABLESIZE -- return number of file descriptors
908 **
909 **	Only on non-BSD systems
910 **
911 **	Parameters:
912 **		none
913 **
914 **	Returns:
915 **		size of file descriptor table
916 **
917 **	Side Effects:
918 **		none
919 */
920 
921 #ifdef SYSTEM5
922 
923 int
924 getdtablesize()
925 {
926 	return NOFILE;
927 }
928 
929 #endif
930 /*
931 **  UNAME -- get the UUCP name of this system.
932 */
933 
934 #ifndef HASUNAME
935 
936 int
937 uname(name)
938 	struct utsname *name;
939 {
940 	FILE *file;
941 	char *n;
942 
943 	name->nodename[0] = '\0';
944 
945 	/* try /etc/whoami -- one line with the node name */
946 	if ((file = fopen("/etc/whoami", "r")) != NULL)
947 	{
948 		(void) fgets(name->nodename, NODE_LENGTH + 1, file);
949 		(void) fclose(file);
950 		n = strchr(name->nodename, '\n');
951 		if (n != NULL)
952 			*n = '\0';
953 		if (name->nodename[0] != '\0')
954 			return (0);
955 	}
956 
957 	/* try /usr/include/whoami.h -- has a #define somewhere */
958 	if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
959 	{
960 		char buf[MAXLINE];
961 
962 		while (fgets(buf, MAXLINE, file) != NULL)
963 			if (sscanf(buf, "#define sysname \"%*[^\"]\"",
964 					NODE_LENGTH, name->nodename) > 0)
965 				break;
966 		(void) fclose(file);
967 		if (name->nodename[0] != '\0')
968 			return (0);
969 	}
970 
971 #ifdef TRUST_POPEN
972 	/*
973 	**  Popen is known to have security holes.
974 	*/
975 
976 	/* try uuname -l to return local name */
977 	if ((file = popen("uuname -l", "r")) != NULL)
978 	{
979 		(void) fgets(name, NODE_LENGTH + 1, file);
980 		(void) pclose(file);
981 		n = strchr(name, '\n');
982 		if (n != NULL)
983 			*n = '\0';
984 		if (name->nodename[0] != '\0')
985 			return (0);
986 	}
987 #endif
988 
989 	return (-1);
990 }
991 #endif /* HASUNAME */
992 /*
993 **  INITGROUPS -- initialize groups
994 **
995 **	Stub implementation for System V style systems
996 */
997 
998 #ifndef HASINITGROUPS
999 # if !defined(SYSTEM5) || defined(hpux)
1000 #  define HASINITGROUPS
1001 # endif
1002 #endif
1003 
1004 #ifndef HASINITGROUPS
1005 
1006 initgroups(name, basegid)
1007 	char *name;
1008 	int basegid;
1009 {
1010 	return 0;
1011 }
1012 
1013 #endif
1014 /*
1015 **  ENOUGHSPACE -- check to see if there is enough free space on the queue fs
1016 **
1017 **	Only implemented if you have statfs.
1018 **
1019 **	Parameters:
1020 **		none.
1021 **
1022 **	Returns:
1023 **		TRUE if there is enough space.
1024 **		FALSE otherwise.
1025 */
1026 
1027 #ifndef HASSTATFS
1028 # if defined(BSD4_4) || defined(__osf__)
1029 #  define HASSTATFS
1030 # endif
1031 #endif
1032 
1033 #ifdef HASSTATFS
1034 # if defined(sgi) || defined(apollo)
1035 #  include <sys/statfs.h>
1036 # else
1037 #  if defined(sun) || defined(hpux)
1038 #   include <sys/vfs.h>
1039 #  else
1040 #   include <sys/mount.h>
1041 #  endif
1042 # endif
1043 #endif
1044 
1045 bool
1046 enoughspace()
1047 {
1048 #ifdef HASSTATFS
1049 # if defined(ultrix)
1050 	struct fs_data fs;
1051 #  define f_bavail	fd_bfreen
1052 # else
1053 	struct statfs fs;
1054 # endif
1055 	extern int errno;
1056 	extern char *errstring();
1057 
1058 	if (MinBlocksFree <= 0)
1059 	{
1060 		if (tTd(4, 80))
1061 			printf("enoughspace: no threshold\n");
1062 		return TRUE;
1063 	}
1064 # if defined(sgi) || defined(apollo)
1065 	if (statfs(QueueDir, &fs, sizeof fs, 0) == 0)
1066 # else
1067 #  if defined(ultrix)
1068 	if (statfs(QueueDir, &fs) > 0)
1069 #  else
1070 	if (statfs(QueueDir, &fs) == 0)
1071 #  endif
1072 # endif
1073 	{
1074 		if (tTd(4, 80))
1075 			printf("enoughspace: bavail=%ld, min=%ld\n",
1076 				fs.f_bavail, MinBlocksFree);
1077 		if (fs.f_bavail < MinBlocksFree)
1078 		{
1079 #ifdef LOG
1080 			if (LogLevel > 0)
1081 				syslog(LOG_ALERT, "%s: low on space (have %ld, need %ld)",
1082 					QueueDir, fs.f_bavail, MinBlocksFree);
1083 #endif
1084 			return FALSE;
1085 		}
1086 	}
1087 	else if (tTd(4, 80))
1088 		printf("enoughspace: min=%ld: %s\n",
1089 			MinBlocksFree, errstring(errno));
1090 #endif
1091 	return TRUE;
1092 }
1093