xref: /csrg-svn/usr.sbin/sendmail/src/conf.c (revision 58082)
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.18 (Berkeley) 02/20/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 	"needexpnnelo",		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 	ReadTimeout = 2 * 60 * 60;		/* option r */
173 	TimeOut = 3 * 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 	return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
763 }
764 /*
765 **  REFUSECONNECTIONS -- decide if connections should be refused
766 **
767 **	Parameters:
768 **		none.
769 **
770 **	Returns:
771 **		TRUE if incoming SMTP connections should be refused
772 **			(for now).
773 **		FALSE if we should accept new work.
774 **
775 **	Side Effects:
776 **		none.
777 */
778 
779 bool
780 refuseconnections()
781 {
782 	/* this is probably too simplistic */
783 	return (CurrentLA > RefuseLA);
784 }
785 /*
786 **  SETPROCTITLE -- set process title for ps
787 **
788 **	Parameters:
789 **		fmt -- a printf style format string.
790 **		a, b, c -- possible parameters to fmt.
791 **
792 **	Returns:
793 **		none.
794 **
795 **	Side Effects:
796 **		Clobbers argv of our main procedure so ps(1) will
797 **		display the title.
798 */
799 
800 /*VARARGS1*/
801 #ifdef __STDC__
802 setproctitle(char *fmt, ...)
803 #else
804 setproctitle(fmt, va_alist)
805 	char *fmt;
806 	va_dcl
807 #endif
808 {
809 # ifdef SETPROCTITLE
810 	register char *p;
811 	register int i;
812 	char buf[MAXLINE];
813 	VA_LOCAL_DECL
814 	extern char **Argv;
815 	extern char *LastArgv;
816 
817 	p = buf;
818 
819 	/* print sendmail: heading for grep */
820 	(void) strcpy(p, "sendmail: ");
821 	p += strlen(p);
822 
823 	/* print the argument string */
824 	VA_START(fmt);
825 	(void) vsprintf(p, fmt, ap);
826 	VA_END;
827 
828 	i = strlen(buf);
829 	if (i > LastArgv - Argv[0] - 2)
830 	{
831 		i = LastArgv - Argv[0] - 2;
832 		buf[i] = '\0';
833 	}
834 	(void) strcpy(Argv[0], buf);
835 	p = &Argv[0][i];
836 	while (p < LastArgv)
837 		*p++ = ' ';
838 # endif /* SETPROCTITLE */
839 }
840 /*
841 **  REAPCHILD -- pick up the body of my child, lest it become a zombie
842 **
843 **	Parameters:
844 **		none.
845 **
846 **	Returns:
847 **		none.
848 **
849 **	Side Effects:
850 **		Picks up extant zombies.
851 */
852 
853 # include <sys/wait.h>
854 
855 void
856 reapchild()
857 {
858 # ifdef WNOHANG
859 	union wait status;
860 
861 	while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
862 		continue;
863 # else /* WNOHANG */
864 	auto int status;
865 
866 	while (wait((int *)&status) > 0)
867 		continue;
868 # endif /* WNOHANG */
869 # ifdef SYSTEM5
870 	(void) signal(SIGCHLD, reapchild);
871 # endif
872 }
873 /*
874 **  UNSETENV -- remove a variable from the environment
875 **
876 **	Not needed on newer systems.
877 **
878 **	Parameters:
879 **		name -- the string name of the environment variable to be
880 **			deleted from the current environment.
881 **
882 **	Returns:
883 **		none.
884 **
885 **	Globals:
886 **		environ -- a pointer to the current environment.
887 **
888 **	Side Effects:
889 **		Modifies environ.
890 */
891 
892 #ifdef UNSETENV
893 
894 void
895 unsetenv(name)
896 	char *name;
897 {
898 	extern char **environ;
899 	register char **pp;
900 	int len = strlen(name);
901 
902 	for (pp = environ; *pp != NULL; pp++)
903 	{
904 		if (strncmp(name, *pp, len) == 0 &&
905 		    ((*pp)[len] == '=' || (*pp)[len] == '\0'))
906 			break;
907 	}
908 
909 	for (; *pp != NULL; pp++)
910 		*pp = pp[1];
911 }
912 
913 #endif /* UNSETENV */
914 /*
915 **  GETDTABLESIZE -- return number of file descriptors
916 **
917 **	Only on non-BSD systems
918 **
919 **	Parameters:
920 **		none
921 **
922 **	Returns:
923 **		size of file descriptor table
924 **
925 **	Side Effects:
926 **		none
927 */
928 
929 #ifdef SYSTEM5
930 
931 int
932 getdtablesize()
933 {
934 	return NOFILE;
935 }
936 
937 #endif
938 /*
939 **  UNAME -- get the UUCP name of this system.
940 */
941 
942 #ifndef HASUNAME
943 
944 int
945 uname(name)
946 	struct utsname *name;
947 {
948 	FILE *file;
949 	char *n;
950 
951 	name->nodename[0] = '\0';
952 
953 	/* try /etc/whoami -- one line with the node name */
954 	if ((file = fopen("/etc/whoami", "r")) != NULL)
955 	{
956 		(void) fgets(name->nodename, NODE_LENGTH + 1, file);
957 		(void) fclose(file);
958 		n = strchr(name->nodename, '\n');
959 		if (n != NULL)
960 			*n = '\0';
961 		if (name->nodename[0] != '\0')
962 			return (0);
963 	}
964 
965 	/* try /usr/include/whoami.h -- has a #define somewhere */
966 	if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
967 	{
968 		char buf[MAXLINE];
969 
970 		while (fgets(buf, MAXLINE, file) != NULL)
971 			if (sscanf(buf, "#define sysname \"%*[^\"]\"",
972 					NODE_LENGTH, name->nodename) > 0)
973 				break;
974 		(void) fclose(file);
975 		if (name->nodename[0] != '\0')
976 			return (0);
977 	}
978 
979 #ifdef TRUST_POPEN
980 	/*
981 	**  Popen is known to have security holes.
982 	*/
983 
984 	/* try uuname -l to return local name */
985 	if ((file = popen("uuname -l", "r")) != NULL)
986 	{
987 		(void) fgets(name, NODE_LENGTH + 1, file);
988 		(void) pclose(file);
989 		n = strchr(name, '\n');
990 		if (n != NULL)
991 			*n = '\0';
992 		if (name->nodename[0] != '\0')
993 			return (0);
994 	}
995 #endif
996 
997 	return (-1);
998 }
999 #endif /* HASUNAME */
1000 /*
1001 **  INITGROUPS -- initialize groups
1002 **
1003 **	Stub implementation for System V style systems
1004 */
1005 
1006 #ifndef HASINITGROUPS
1007 # if !defined(SYSTEM5) || defined(hpux)
1008 #  define HASINITGROUPS
1009 # endif
1010 #endif
1011 
1012 #ifndef HASINITGROUPS
1013 
1014 initgroups(name, basegid)
1015 	char *name;
1016 	int basegid;
1017 {
1018 	return 0;
1019 }
1020 
1021 #endif
1022 /*
1023 **  ENOUGHSPACE -- check to see if there is enough free space on the queue fs
1024 **
1025 **	Only implemented if you have statfs.
1026 **
1027 **	Parameters:
1028 **		none.
1029 **
1030 **	Returns:
1031 **		TRUE if there is enough space.
1032 **		FALSE otherwise.
1033 */
1034 
1035 #ifndef HASSTATFS
1036 # if defined(BSD4_4) || defined(__osf__)
1037 #  define HASSTATFS
1038 # endif
1039 #endif
1040 
1041 #ifdef HASSTATFS
1042 #include <sys/mount.h>
1043 #endif
1044 
1045 bool
1046 enoughspace()
1047 {
1048 #ifdef HASSTATFS
1049 	struct statfs fs;
1050 	extern int errno;
1051 	extern char *errstring();
1052 
1053 	if (MinBlocksFree > 0 && statfs(QueueDir, &fs) >= 0)
1054 	{
1055 		if (tTd(4, 80))
1056 			printf("enoughspace: bfree=%ld, min=%ld\n",
1057 				fs.f_bfree, MinBlocksFree);
1058 		if (fs.f_bfree < MinBlocksFree)
1059 			return FALSE;
1060 	}
1061 	else if (tTd(4, 80))
1062 		printf("enoughspace: min=%ld: %s\n",
1063 			MinBlocksFree, errstring(errno));
1064 #endif
1065 	return TRUE;
1066 }
1067