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