This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.sbin / sendmail / src / conf.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1983 Eric P. Allman
6f14531a
RG
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
15637ed4
RG
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
d747e748 36static char sccsid[] = "@(#)conf.c 8.42 (Berkeley) 10/21/93";
15637ed4
RG
37#endif /* not lint */
38
d747e748
JH
39# include "sendmail.h"
40# include "pathnames.h"
15637ed4
RG
41# include <sys/ioctl.h>
42# include <sys/param.h>
43# include <pwd.h>
15637ed4
RG
44
45/*
46** CONF.C -- Sendmail Configuration Tables.
47**
48** Defines the configuration of this installation.
49**
15637ed4
RG
50** Configuration Variables:
51** HdrInfo -- a table describing well-known header fields.
52** Each entry has the field name and some flags,
53** which are described in sendmail.h.
54**
55** Notes:
56** I have tried to put almost all the reasonable
57** configuration information into the configuration
58** file read at runtime. My intent is that anything
59** here is a function of the version of UNIX you
60** are running, or is really static -- for example
61** the headers are a superset of widely used
62** protocols. If you find yourself playing with
63** this file too much, you may be making a mistake!
64*/
65
66
67
68
69/*
70** Header info table
71** Final (null) entry contains the flags used for any other field.
72**
73** Not all of these are actually handled specially by sendmail
74** at this time. They are included as placeholders, to let
75** you know that "someday" I intend to have sendmail do
76** something with them.
77*/
78
79struct hdrinfo HdrInfo[] =
80{
81 /* originator fields, most to least significant */
82 "resent-sender", H_FROM|H_RESENT,
83 "resent-from", H_FROM|H_RESENT,
84 "resent-reply-to", H_FROM|H_RESENT,
85 "sender", H_FROM,
86 "from", H_FROM,
87 "reply-to", H_FROM,
88 "full-name", H_ACHECK,
d747e748 89 "return-receipt-to", H_FROM|H_RECEIPTTO,
6f14531a
RG
90 "errors-to", H_FROM|H_ERRORSTO,
91
15637ed4
RG
92 /* destination fields */
93 "to", H_RCPT,
94 "resent-to", H_RCPT|H_RESENT,
95 "cc", H_RCPT,
96 "resent-cc", H_RCPT|H_RESENT,
97 "bcc", H_RCPT|H_ACHECK,
98 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT,
6f14531a
RG
99 "apparently-to", H_RCPT,
100
15637ed4
RG
101 /* message identification and control */
102 "message-id", 0,
103 "resent-message-id", H_RESENT,
104 "message", H_EOH,
105 "text", H_EOH,
6f14531a 106
15637ed4
RG
107 /* date fields */
108 "date", 0,
109 "resent-date", H_RESENT,
6f14531a 110
15637ed4
RG
111 /* trace fields */
112 "received", H_TRACE|H_FORCE,
6f14531a 113 "x400-received", H_TRACE|H_FORCE,
15637ed4
RG
114 "via", H_TRACE|H_FORCE,
115 "mail-from", H_TRACE|H_FORCE,
116
6f14531a
RG
117 /* miscellaneous fields */
118 "comments", H_FORCE,
3a363396 119 "return-path", H_FORCE|H_ACHECK,
6f14531a 120
15637ed4
RG
121 NULL, 0,
122};
123
124
6f14531a 125
15637ed4 126/*
6f14531a 127** Location of system files/databases/etc.
15637ed4
RG
128*/
129
6f14531a 130char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */
15637ed4
RG
131
132
133
134/*
6f14531a 135** Privacy values
15637ed4
RG
136*/
137
6f14531a
RG
138struct prival PrivacyValues[] =
139{
140 "public", PRIV_PUBLIC,
141 "needmailhelo", PRIV_NEEDMAILHELO,
142 "needexpnhelo", PRIV_NEEDEXPNHELO,
143 "needvrfyhelo", PRIV_NEEDVRFYHELO,
144 "noexpn", PRIV_NOEXPN,
145 "novrfy", PRIV_NOVRFY,
d747e748
JH
146 "restrictmailq", PRIV_RESTRICTMAILQ,
147 "restrictqrun", PRIV_RESTRICTQRUN,
6f14531a
RG
148 "authwarnings", PRIV_AUTHWARNINGS,
149 "goaway", PRIV_GOAWAY,
150 NULL, 0,
151};
15637ed4
RG
152
153
154
155/*
156** Miscellaneous stuff.
157*/
158
159int DtableSize = 50; /* max open files; reset in 4.2bsd */
d747e748
JH
160
161
162/*
163** Following should be config parameters (and probably will be in
164** future releases). In the meantime, setting these is considered
165** unsupported, and is intentionally undocumented.
166*/
167
168#ifdef BROKENSMTPPEERS
169bool BrokenSmtpPeers = TRUE; /* set if you have broken SMTP peers */
170#else
171bool BrokenSmtpPeers = FALSE; /* set if you have broken SMTP peers */
172#endif
173#ifdef NOLOOPBACKCHECK
174bool CheckLoopBack = FALSE; /* set to check HELO loopback */
175#else
176bool CheckLoopBack = TRUE; /* set to check HELO loopback */
177#endif
178
15637ed4
RG
179\f/*
180** SETDEFAULTS -- set default values
181**
182** Because of the way freezing is done, these must be initialized
183** using direct code.
184**
185** Parameters:
6f14531a 186** e -- the default envelope.
15637ed4
RG
187**
188** Returns:
189** none.
190**
191** Side Effects:
192** Initializes a bunch of global variables to their
193** default values.
194*/
195
6f14531a
RG
196#define DAYS * 24 * 60 * 60
197
198setdefaults(e)
199 register ENVELOPE *e;
15637ed4 200{
6f14531a
RG
201 SpaceSub = ' '; /* option B */
202 QueueLA = 8; /* option x */
203 RefuseLA = 12; /* option X */
204 WkRecipFact = 30000L; /* option y */
205 WkClassFact = 1800L; /* option z */
206 WkTimeFact = 90000L; /* option Z */
207 QueueFactor = WkRecipFact * 20; /* option q */
3a363396 208 FileMode = (RealUid != geteuid()) ? 0644 : 0600;
6f14531a
RG
209 /* option F */
210 DefUid = 1; /* option u */
211 DefGid = 1; /* option g */
212 CheckpointInterval = 10; /* option C */
213 MaxHopCount = 25; /* option h */
214 e->e_sendmode = SM_FORK; /* option d */
215 e->e_errormode = EM_PRINT; /* option e */
216 SevenBit = FALSE; /* option 7 */
217 MaxMciCache = 1; /* option k */
218 MciCacheTimeout = 300; /* option K */
219 LogLevel = 9; /* option L */
220 settimeouts(NULL); /* option r */
221 TimeOuts.to_q_return = 5 DAYS; /* option T */
222 TimeOuts.to_q_warning = 0; /* option T */
223 PrivacyFlags = 0; /* option p */
15637ed4 224 setdefuser();
6f14531a
RG
225 setupmaps();
226 setupmailers();
15637ed4
RG
227}
228
229
230/*
231** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
232*/
233
234setdefuser()
235{
236 struct passwd *defpwent;
6f14531a 237 static char defuserbuf[40];
15637ed4 238
6f14531a 239 DefUser = defuserbuf;
15637ed4 240 if ((defpwent = getpwuid(DefUid)) != NULL)
6f14531a 241 strcpy(defuserbuf, defpwent->pw_name);
15637ed4 242 else
6f14531a
RG
243 strcpy(defuserbuf, "nobody");
244}
245\f/*
246** HOST_MAP_INIT -- initialize host class structures
247*/
248
249bool
250host_map_init(map, args)
251 MAP *map;
252 char *args;
253{
254 register char *p = args;
255
256 for (;;)
257 {
258 while (isascii(*p) && isspace(*p))
259 p++;
260 if (*p != '-')
261 break;
262 switch (*++p)
263 {
264 case 'a':
265 map->map_app = ++p;
266 break;
267 }
268 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
269 p++;
270 if (*p != '\0')
271 *p++ = '\0';
272 }
273 if (map->map_app != NULL)
274 map->map_app = newstr(map->map_app);
275 return TRUE;
15637ed4 276}
6f14531a
RG
277\f/*
278** SETUPMAILERS -- initialize default mailers
279*/
15637ed4 280
6f14531a
RG
281setupmailers()
282{
283 char buf[100];
15637ed4 284
6f14531a
RG
285 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u");
286 makemailer(buf);
287
288 strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE");
289 makemailer(buf);
290
291 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE");
292 makemailer(buf);
293}
294\f/*
295** SETUPMAPS -- set up map classes
296*/
297
298#define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \
299 { \
300 extern bool parse __P((MAP *, char *)); \
301 extern bool open __P((MAP *, int)); \
302 extern void close __P((MAP *)); \
303 extern char *lookup __P((MAP *, char *, char **, int *)); \
304 extern void store __P((MAP *, char *, char *)); \
305 s = stab(name, ST_MAPCLASS, ST_ENTER); \
306 s->s_mapclass.map_cname = name; \
307 s->s_mapclass.map_ext = ext; \
308 s->s_mapclass.map_cflags = flags; \
309 s->s_mapclass.map_parse = parse; \
310 s->s_mapclass.map_open = open; \
311 s->s_mapclass.map_close = close; \
312 s->s_mapclass.map_lookup = lookup; \
313 s->s_mapclass.map_store = store; \
314 }
315
316setupmaps()
317{
318 register STAB *s;
319
320#ifdef NEWDB
321 MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
322 map_parseargs, hash_map_open, db_map_close,
323 db_map_lookup, db_map_store);
324 MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
325 map_parseargs, bt_map_open, db_map_close,
326 db_map_lookup, db_map_store);
327#endif
328
329#ifdef NDBM
330 MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
331 map_parseargs, ndbm_map_open, ndbm_map_close,
332 ndbm_map_lookup, ndbm_map_store);
333#endif
334
335#ifdef NIS
336 MAPDEF("nis", NULL, MCF_ALIASOK,
337 map_parseargs, nis_map_open, nis_map_close,
338 nis_map_lookup, nis_map_store);
339#endif
340
341 MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
342 map_parseargs, stab_map_open, stab_map_close,
343 stab_map_lookup, stab_map_store);
344
345 MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE,
346 map_parseargs, impl_map_open, impl_map_close,
347 impl_map_lookup, impl_map_store);
348
349 /* host DNS lookup */
350 MAPDEF("host", NULL, 0,
351 host_map_init, null_map_open, null_map_close,
352 host_map_lookup, null_map_store);
353
354 /* dequote map */
355 MAPDEF("dequote", NULL, 0,
356 dequote_init, null_map_open, null_map_close,
357 dequote_map, null_map_store);
358
359#if 0
360# ifdef USERDB
361 /* user database */
362 MAPDEF("udb", ".db", 0,
363 udb_map_parse, null_map_open, null_map_close,
364 udb_map_lookup, null_map_store);
365# endif
366#endif
367}
368
369#undef MAPDEF
370\f/*
15637ed4
RG
371** USERNAME -- return the user id of the logged in user.
372**
373** Parameters:
374** none.
375**
376** Returns:
377** The login name of the logged in user.
378**
379** Side Effects:
380** none.
381**
382** Notes:
383** The return value is statically allocated.
384*/
385
386char *
387username()
388{
389 static char *myname = NULL;
390 extern char *getlogin();
391 register struct passwd *pw;
392
393 /* cache the result */
394 if (myname == NULL)
395 {
396 myname = getlogin();
397 if (myname == NULL || myname[0] == '\0')
398 {
3a363396 399 pw = getpwuid(RealUid);
15637ed4
RG
400 if (pw != NULL)
401 myname = newstr(pw->pw_name);
402 }
403 else
404 {
3a363396 405 uid_t uid = RealUid;
15637ed4
RG
406
407 myname = newstr(myname);
408 if ((pw = getpwnam(myname)) == NULL ||
6f14531a 409 (uid != 0 && uid != pw->pw_uid))
15637ed4 410 {
6f14531a 411 pw = getpwuid(uid);
15637ed4
RG
412 if (pw != NULL)
413 myname = newstr(pw->pw_name);
414 }
415 }
416 if (myname == NULL || myname[0] == '\0')
417 {
6f14531a 418 syserr("554 Who are you?");
15637ed4
RG
419 myname = "postmaster";
420 }
421 }
422
423 return (myname);
424}
425\f/*
426** TTYPATH -- Get the path of the user's tty
427**
428** Returns the pathname of the user's tty. Returns NULL if
429** the user is not logged in or if s/he has write permission
430** denied.
431**
432** Parameters:
433** none
434**
435** Returns:
436** pathname of the user's tty.
437** NULL if not logged in or write permission denied.
438**
439** Side Effects:
440** none.
441**
442** WARNING:
443** Return value is in a local buffer.
444**
445** Called By:
446** savemail
447*/
448
15637ed4
RG
449char *
450ttypath()
451{
452 struct stat stbuf;
453 register char *pathn;
454 extern char *ttyname();
455 extern char *getlogin();
456
457 /* compute the pathname of the controlling tty */
458 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
459 (pathn = ttyname(0)) == NULL)
460 {
461 errno = 0;
462 return (NULL);
463 }
464
465 /* see if we have write permission */
466 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode))
467 {
468 errno = 0;
469 return (NULL);
470 }
471
472 /* see if the user is logged in */
473 if (getlogin() == NULL)
474 return (NULL);
475
476 /* looks good */
477 return (pathn);
478}
479\f/*
480** CHECKCOMPAT -- check for From and To person compatible.
481**
482** This routine can be supplied on a per-installation basis
483** to determine whether a person is allowed to send a message.
484** This allows restriction of certain types of internet
485** forwarding or registration of users.
486**
487** If the hosts are found to be incompatible, an error
6f14531a 488** message should be given using "usrerr" and 0 should
15637ed4
RG
489** be returned.
490**
491** 'NoReturn' can be set to suppress the return-to-sender
492** function; this should be done on huge messages.
493**
494** Parameters:
495** to -- the person being sent to.
496**
497** Returns:
6f14531a 498** an exit status
15637ed4
RG
499**
500** Side Effects:
501** none (unless you include the usrerr stuff)
502*/
503
6f14531a 504checkcompat(to, e)
15637ed4 505 register ADDRESS *to;
6f14531a 506 register ENVELOPE *e;
15637ed4
RG
507{
508# ifdef lint
509 if (to == NULL)
510 to++;
d747e748
JH
511# endif /* lint */
512
513 if (tTd(49, 1))
514 printf("checkcompat(to=%s, from=%s)\n",
515 to->q_paddr, e->e_from.q_paddr);
516
15637ed4
RG
517# ifdef EXAMPLE_CODE
518 /* this code is intended as an example only */
519 register STAB *s;
520
521 s = stab("arpa", ST_MAILER, ST_FIND);
6f14531a 522 if (s != NULL && e->e_from.q_mailer != LocalMailer &&
15637ed4
RG
523 to->q_mailer == s->s_mailer)
524 {
6f14531a 525 usrerr("553 No ARPA mail through this machine: see your system administration");
15637ed4 526 /* NoReturn = TRUE; to supress return copy */
6f14531a 527 return (EX_UNAVAILABLE);
15637ed4 528 }
6f14531a
RG
529# endif /* EXAMPLE_CODE */
530 return (EX_OK);
15637ed4
RG
531}
532\f/*
d747e748
JH
533** SETSIGNAL -- set a signal handler
534**
535** This is essentially old BSD "signal(3)".
536*/
537
538sigfunc_t
539setsignal(sig, handler)
540 int sig;
541 sigfunc_t handler;
542{
543#if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE)
544 return signal(sig, handler);
545#else
546 struct sigaction n, o;
547
548 bzero(&n, sizeof n);
549 n.sa_handler = handler;
550 if (sigaction(sig, &n, &o) < 0)
551 return SIG_ERR;
552 return o.sa_handler;
553#endif
554}
555\f/*
15637ed4
RG
556** HOLDSIGS -- arrange to hold all signals
557**
558** Parameters:
559** none.
560**
561** Returns:
562** none.
563**
564** Side Effects:
565** Arranges that signals are held.
566*/
567
568holdsigs()
569{
570}
571\f/*
572** RLSESIGS -- arrange to release all signals
573**
574** This undoes the effect of holdsigs.
575**
576** Parameters:
577** none.
578**
579** Returns:
580** none.
581**
582** Side Effects:
583** Arranges that signals are released.
584*/
585
586rlsesigs()
587{
588}
589\f/*
d747e748
JH
590** INIT_MD -- do machine dependent initializations
591**
592** Systems that have global modes that should be set should do
593** them here rather than in main.
594*/
595
596#ifdef _AUX_SOURCE
597# include <compat.h>
598#endif
599
600init_md()
601{
602#ifdef _AUX_SOURCE
603 setcompat(getcompat() | COMPAT_BSDPROT);
604#endif
605}
606\f/*
15637ed4
RG
607** GETLA -- get the current load average
608**
609** This code stolen from la.c.
610**
611** Parameters:
612** none.
613**
614** Returns:
615** The current load average as an integer.
616**
617** Side Effects:
618** none.
619*/
620
6f14531a
RG
621/* try to guess what style of load average we have */
622#define LA_ZERO 1 /* always return load average as zero */
d747e748 623#define LA_INT 2 /* read kmem for avenrun; interpret as long */
6f14531a
RG
624#define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */
625#define LA_SUBR 4 /* call getloadavg */
d747e748
JH
626#define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */
627#define LA_SHORT 6 /* read kmem for avenrun; interpret as short */
6f14531a 628
d747e748 629/* do guesses based on general OS type */
6f14531a 630#ifndef LA_TYPE
d747e748 631# define LA_TYPE LA_ZERO
15637ed4 632#endif
15637ed4 633
d747e748 634#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
15637ed4
RG
635
636#include <nlist.h>
637
6f14531a 638#ifndef LA_AVENRUN
d747e748
JH
639# ifdef SYSTEM5
640# define LA_AVENRUN "avenrun"
641# else
642# define LA_AVENRUN "_avenrun"
643# endif
6f14531a
RG
644#endif
645
646/* _PATH_UNIX should be defined in <paths.h> */
647#ifndef _PATH_UNIX
d747e748
JH
648# if defined(SYSTEM5)
649# define _PATH_UNIX "/unix"
650# else
651# define _PATH_UNIX "/vmunix"
652# endif
6f14531a
RG
653#endif
654
15637ed4
RG
655struct nlist Nl[] =
656{
6f14531a 657 { LA_AVENRUN },
15637ed4
RG
658#define X_AVENRUN 0
659 { 0 },
660};
661
6f14531a
RG
662#ifndef FSHIFT
663# if defined(unixpc)
664# define FSHIFT 5
665# endif
15637ed4 666
6f14531a
RG
667# if defined(__alpha)
668# define FSHIFT 10
669# endif
670
d747e748 671# if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
6f14531a
RG
672# define FSHIFT 8
673# endif
674#endif
675
d747e748 676#if ((LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)) && !defined(FSCALE)
6f14531a
RG
677# define FSCALE (1 << FSHIFT)
678#endif
15637ed4
RG
679
680getla()
681{
682 static int kmem = -1;
6f14531a 683#if LA_TYPE == LA_INT
15637ed4 684 long avenrun[3];
6f14531a 685#else
d747e748
JH
686# if LA_TYPE == LA_SHORT
687 short avenrun[3];
688# else
6f14531a 689 double avenrun[3];
d747e748 690# endif
6f14531a 691#endif
15637ed4 692 extern off_t lseek();
6f14531a 693 extern int errno;
15637ed4
RG
694
695 if (kmem < 0)
696 {
697 kmem = open("/dev/kmem", 0, 0);
698 if (kmem < 0)
6f14531a
RG
699 {
700 if (tTd(3, 1))
701 printf("getla: open(/dev/kmem): %s\n",
702 errstring(errno));
15637ed4 703 return (-1);
6f14531a
RG
704 }
705 (void) fcntl(kmem, F_SETFD, 1);
706 if (nlist(_PATH_UNIX, Nl) < 0)
707 {
708 if (tTd(3, 1))
709 printf("getla: nlist(%s): %s\n", _PATH_UNIX,
710 errstring(errno));
15637ed4 711 return (-1);
6f14531a
RG
712 }
713 if (Nl[X_AVENRUN].n_value == 0)
714 {
715 if (tTd(3, 1))
716 printf("getla: nlist(%s, %s) ==> 0\n",
717 _PATH_UNIX, LA_AVENRUN);
718 return (-1);
719 }
15637ed4 720 }
6f14531a
RG
721 if (tTd(3, 20))
722 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value);
15637ed4
RG
723 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
724 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
725 {
726 /* thank you Ian */
6f14531a
RG
727 if (tTd(3, 1))
728 printf("getla: lseek or read: %s\n", errstring(errno));
15637ed4
RG
729 return (-1);
730 }
d747e748 731#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
6f14531a
RG
732 if (tTd(3, 5))
733 {
734 printf("getla: avenrun = %d", avenrun[0]);
735 if (tTd(3, 15))
736 printf(", %d, %d", avenrun[1], avenrun[2]);
737 printf("\n");
738 }
739 if (tTd(3, 1))
740 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
15637ed4 741 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
6f14531a
RG
742#else
743 if (tTd(3, 5))
744 {
745 printf("getla: avenrun = %g", avenrun[0]);
746 if (tTd(3, 15))
747 printf(", %g, %g", avenrun[1], avenrun[2]);
748 printf("\n");
749 }
750 if (tTd(3, 1))
751 printf("getla: %d\n", (int) (avenrun[0] +0.5));
752 return ((int) (avenrun[0] + 0.5));
753#endif
754}
755
756#else
757#if LA_TYPE == LA_SUBR
758
d747e748
JH
759#ifdef DGUX
760
761#include <sys/dg_sys_info.h>
762
763int getla()
764{
765 struct dg_sys_info_load_info load_info;
766
767 dg_sys_info((long *)&load_info,
768 DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
769
770 return((int) (load_info.one_minute + 0.5));
771}
772
773#else
774
6f14531a
RG
775getla()
776{
777 double avenrun[3];
778
779 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
780 {
781 if (tTd(3, 1))
782 perror("getla: getloadavg failed:");
783 return (-1);
784 }
785 if (tTd(3, 1))
786 printf("getla: %d\n", (int) (avenrun[0] +0.5));
787 return ((int) (avenrun[0] + 0.5));
788}
789
d747e748
JH
790#endif /* DGUX */
791#else
792#if LA_TYPE == LA_MACH
793
794/*
795** This has been tested on NeXT release 2.1.
796*/
797
798#include <mach.h>
799
800getla()
801{
802 processor_set_t default_set;
803 kern_return_t error;
804 unsigned int info_count;
805 struct processor_set_basic_info info;
806 host_t host;
807
808 error = processor_set_default(host_self(), &default_set);
809 if (error != KERN_SUCCESS)
810 return -1;
811 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
812 if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO,
813 &host, (processor_set_info_t)&info,
814 &info_count) != KERN_SUCCESS)
815 {
816 return -1;
817 }
818 return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
819}
820
821
6f14531a
RG
822#else
823
824getla()
825{
826 if (tTd(3, 1))
827 printf("getla: ZERO\n");
828 return (0);
15637ed4
RG
829}
830
d747e748 831#endif
6f14531a
RG
832#endif
833#endif
15637ed4
RG
834\f/*
835** SHOULDQUEUE -- should this message be queued or sent?
836**
837** Compares the message cost to the load average to decide.
838**
839** Parameters:
840** pri -- the priority of the message in question.
6f14531a 841** ctime -- the message creation time.
15637ed4
RG
842**
843** Returns:
844** TRUE -- if this message should be queued up for the
845** time being.
846** FALSE -- if the load is low enough to send this message.
847**
848** Side Effects:
849** none.
850*/
851
852bool
6f14531a 853shouldqueue(pri, ctime)
15637ed4 854 long pri;
6f14531a 855 time_t ctime;
15637ed4 856{
6f14531a 857 if (CurrentLA < QueueLA)
15637ed4 858 return (FALSE);
6f14531a
RG
859 if (CurrentLA >= RefuseLA)
860 return (TRUE);
861 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1)));
862}
863\f/*
864** REFUSECONNECTIONS -- decide if connections should be refused
865**
866** Parameters:
867** none.
868**
869** Returns:
870** TRUE if incoming SMTP connections should be refused
871** (for now).
872** FALSE if we should accept new work.
873**
874** Side Effects:
875** none.
876*/
877
878bool
879refuseconnections()
880{
881#ifdef XLA
882 if (!xla_smtp_ok())
883 return TRUE;
884#endif
885
886 /* this is probably too simplistic */
887 return (CurrentLA >= RefuseLA);
15637ed4
RG
888}
889\f/*
890** SETPROCTITLE -- set process title for ps
891**
892** Parameters:
893** fmt -- a printf style format string.
894** a, b, c -- possible parameters to fmt.
895**
896** Returns:
897** none.
898**
899** Side Effects:
900** Clobbers argv of our main procedure so ps(1) will
901** display the title.
902*/
903
6f14531a
RG
904#ifdef SETPROCTITLE
905# ifdef __hpux
906# include <sys/pstat.h>
907# endif
908# ifdef BSD4_4
909# include <machine/vmparam.h>
910# include <sys/exec.h>
d747e748
JH
911# ifdef __bsdi__
912# undef PS_STRINGS /* BSDI 1.0 doesn't do PS_STRINGS as we expect */
913# endif
6f14531a
RG
914# ifdef PS_STRINGS
915# define SETPROC_STATIC static
916# endif
917# endif
918# ifndef SETPROC_STATIC
919# define SETPROC_STATIC
920# endif
921#endif
922
15637ed4 923/*VARARGS1*/
6f14531a
RG
924#ifdef __STDC__
925setproctitle(char *fmt, ...)
926#else
927setproctitle(fmt, va_alist)
15637ed4 928 char *fmt;
6f14531a
RG
929 va_dcl
930#endif
15637ed4
RG
931{
932# ifdef SETPROCTITLE
933 register char *p;
934 register int i;
6f14531a
RG
935 SETPROC_STATIC char buf[MAXLINE];
936 VA_LOCAL_DECL
937# ifdef __hpux
938 union pstun pst;
939# endif
15637ed4
RG
940 extern char **Argv;
941 extern char *LastArgv;
15637ed4 942
6f14531a 943 p = buf;
15637ed4 944
6f14531a
RG
945 /* print sendmail: heading for grep */
946 (void) strcpy(p, "sendmail: ");
947 p += strlen(p);
948
949 /* print the argument string */
950 VA_START(fmt);
951 (void) vsprintf(p, fmt, ap);
952 VA_END;
15637ed4
RG
953
954 i = strlen(buf);
6f14531a
RG
955
956# ifdef __hpux
957 pst.pst_command = buf;
958 pstat(PSTAT_SETCMD, pst, i, 0, 0);
959# else
960# ifdef PS_STRINGS
961 PS_STRINGS->ps_nargvstr = 1;
962 PS_STRINGS->ps_argvstr = buf;
963# else
964 if (i > LastArgv - Argv[0] - 2)
15637ed4 965 {
6f14531a 966 i = LastArgv - Argv[0] - 2;
15637ed4
RG
967 buf[i] = '\0';
968 }
6f14531a
RG
969 (void) strcpy(Argv[0], buf);
970 p = &Argv[0][i];
15637ed4
RG
971 while (p < LastArgv)
972 *p++ = ' ';
6f14531a
RG
973# endif
974# endif
975# endif /* SETPROCTITLE */
15637ed4
RG
976}
977\f/*
978** REAPCHILD -- pick up the body of my child, lest it become a zombie
979**
980** Parameters:
981** none.
982**
983** Returns:
984** none.
985**
986** Side Effects:
987** Picks up extant zombies.
988*/
989
15637ed4
RG
990void
991reapchild()
992{
d747e748
JH
993 int olderrno = errno;
994# ifdef HASWAITPID
6f14531a
RG
995 auto int status;
996 int count;
997 int pid;
998
999 count = 0;
1000 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
1001 {
1002 if (count++ > 1000)
1003 {
1004 syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x",
1005 pid, status);
1006 break;
1007 }
1008 }
1009# else
15637ed4
RG
1010# ifdef WNOHANG
1011 union wait status;
1012
3a363396 1013 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
15637ed4 1014 continue;
6f14531a 1015# else /* WNOHANG */
15637ed4
RG
1016 auto int status;
1017
6f14531a 1018 while (wait(&status) > 0)
15637ed4 1019 continue;
6f14531a
RG
1020# endif /* WNOHANG */
1021# endif
d747e748
JH
1022# ifdef SYS5SIGNALS
1023 (void) setsignal(SIGCHLD, reapchild);
6f14531a 1024# endif
d747e748 1025 errno = olderrno;
6f14531a
RG
1026}
1027\f/*
1028** UNSETENV -- remove a variable from the environment
1029**
1030** Not needed on newer systems.
1031**
1032** Parameters:
1033** name -- the string name of the environment variable to be
1034** deleted from the current environment.
1035**
1036** Returns:
1037** none.
1038**
1039** Globals:
1040** environ -- a pointer to the current environment.
1041**
1042** Side Effects:
1043** Modifies environ.
1044*/
1045
d747e748 1046#ifndef HASUNSETENV
6f14531a
RG
1047
1048void
1049unsetenv(name)
1050 char *name;
1051{
1052 extern char **environ;
1053 register char **pp;
1054 int len = strlen(name);
1055
1056 for (pp = environ; *pp != NULL; pp++)
1057 {
1058 if (strncmp(name, *pp, len) == 0 &&
1059 ((*pp)[len] == '=' || (*pp)[len] == '\0'))
1060 break;
1061 }
1062
1063 for (; *pp != NULL; pp++)
1064 *pp = pp[1];
1065}
1066
d747e748 1067#endif
6f14531a
RG
1068\f/*
1069** GETDTABLESIZE -- return number of file descriptors
1070**
1071** Only on non-BSD systems
1072**
1073** Parameters:
1074** none
1075**
1076** Returns:
1077** size of file descriptor table
1078**
1079** Side Effects:
1080** none
1081*/
1082
3a363396
NW
1083#ifdef SOLARIS
1084# include <sys/resource.h>
1085#endif
6f14531a
RG
1086
1087int
3a363396 1088getdtsize()
6f14531a 1089{
3a363396
NW
1090#ifdef RLIMIT_NOFILE
1091 struct rlimit rl;
1092
1093 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
1094 return rl.rlim_cur;
1095#endif
1096
d747e748 1097# ifdef HASGETDTABLESIZE
3a363396 1098 return getdtablesize();
d747e748
JH
1099# else
1100# ifdef _SC_OPEN_MAX
1101 return sysconf(_SC_OPEN_MAX);
3a363396 1102# else
6f14531a 1103 return NOFILE;
3a363396 1104# endif
6f14531a
RG
1105# endif
1106}
6f14531a
RG
1107\f/*
1108** UNAME -- get the UUCP name of this system.
1109*/
1110
1111#ifndef HASUNAME
1112
1113int
1114uname(name)
1115 struct utsname *name;
1116{
1117 FILE *file;
1118 char *n;
1119
1120 name->nodename[0] = '\0';
1121
1122 /* try /etc/whoami -- one line with the node name */
1123 if ((file = fopen("/etc/whoami", "r")) != NULL)
1124 {
1125 (void) fgets(name->nodename, NODE_LENGTH + 1, file);
1126 (void) fclose(file);
1127 n = strchr(name->nodename, '\n');
1128 if (n != NULL)
1129 *n = '\0';
1130 if (name->nodename[0] != '\0')
1131 return (0);
1132 }
1133
1134 /* try /usr/include/whoami.h -- has a #define somewhere */
1135 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
1136 {
1137 char buf[MAXLINE];
1138
1139 while (fgets(buf, MAXLINE, file) != NULL)
1140 if (sscanf(buf, "#define sysname \"%*[^\"]\"",
1141 NODE_LENGTH, name->nodename) > 0)
1142 break;
1143 (void) fclose(file);
1144 if (name->nodename[0] != '\0')
1145 return (0);
1146 }
1147
1148#ifdef TRUST_POPEN
1149 /*
1150 ** Popen is known to have security holes.
1151 */
1152
1153 /* try uuname -l to return local name */
1154 if ((file = popen("uuname -l", "r")) != NULL)
1155 {
1156 (void) fgets(name, NODE_LENGTH + 1, file);
1157 (void) pclose(file);
1158 n = strchr(name, '\n');
1159 if (n != NULL)
1160 *n = '\0';
1161 if (name->nodename[0] != '\0')
1162 return (0);
1163 }
1164#endif
1165
1166 return (-1);
1167}
1168#endif /* HASUNAME */
1169\f/*
1170** INITGROUPS -- initialize groups
1171**
1172** Stub implementation for System V style systems
1173*/
1174
6f14531a
RG
1175#ifndef HASINITGROUPS
1176
1177initgroups(name, basegid)
1178 char *name;
1179 int basegid;
1180{
1181 return 0;
1182}
1183
1184#endif
1185\f/*
1186** SETSID -- set session id (for non-POSIX systems)
1187*/
1188
1189#ifndef HASSETSID
1190
3a363396
NW
1191pid_t
1192setsid __P ((void))
6f14531a 1193{
d747e748
JH
1194#ifdef TIOCNOTTY
1195 int fd;
1196
1197 fd = open("/dev/tty", 2);
1198 if (fd >= 0)
1199 {
1200 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
1201 (void) close(fd);
1202 }
1203#endif /* TIOCNOTTY */
1204# ifdef SYS5SETPGRP
3a363396
NW
1205 return setpgrp();
1206# else
d747e748 1207 return setpgid(0, getpid());
6f14531a
RG
1208# endif
1209}
1210
1211#endif
1212\f/*
d747e748
JH
1213** DGUX_INET_ADDR -- inet_addr for DG/UX
1214**
1215** Data General DG/UX version of inet_addr returns a struct in_addr
1216** instead of a long. This patches things.
1217*/
1218
1219#ifdef DGUX
1220
1221#undef inet_addr
1222
1223long
1224dgux_inet_addr(host)
1225 char *host;
1226{
1227 struct in_addr haddr;
1228
1229 haddr = inet_addr(host);
1230 return haddr.s_addr;
1231}
1232
1233#endif
1234\f/*
1235** GETOPT -- for old systems or systems with bogus implementations
1236*/
1237
1238#ifdef NEEDGETOPT
1239
1240/*
1241 * Copyright (c) 1985 Regents of the University of California.
1242 * All rights reserved. The Berkeley software License Agreement
1243 * specifies the terms and conditions for redistribution.
1244 */
1245
1246
1247/*
1248** this version hacked to add `atend' flag to allow state machine
1249** to reset if invoked by the program to scan args for a 2nd time
1250*/
1251
1252#if defined(LIBC_SCCS) && !defined(lint)
1253static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86";
1254#endif /* LIBC_SCCS and not lint */
1255
1256#include <stdio.h>
1257
1258/*
1259 * get option letter from argument vector
1260 */
1261int opterr = 1, /* if error message should be printed */
1262 optind = 1, /* index into parent argv vector */
1263 optopt; /* character checked for validity */
1264char *optarg; /* argument associated with option */
1265
1266#define BADCH (int)'?'
1267#define EMSG ""
1268#define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
1269 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
1270
1271getopt(nargc,nargv,ostr)
1272int nargc;
1273char **nargv,
1274 *ostr;
1275{
1276 static char *place = EMSG; /* option letter processing */
1277 static char atend = 0;
1278 register char *oli; /* option letter list index */
1279
1280 if (atend) {
1281 atend = 0;
1282 place = EMSG;
1283 }
1284 if(!*place) { /* update scanning pointer */
1285 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
1286 atend++;
1287 return(EOF);
1288 }
1289 if (*place == '-') { /* found "--" */
1290 ++optind;
1291 atend++;
1292 return(EOF);
1293 }
1294 } /* option letter okay? */
1295 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
1296 if (!*place) ++optind;
1297 tell(": illegal option -- ");
1298 }
1299 if (*++oli != ':') { /* don't need argument */
1300 optarg = NULL;
1301 if (!*place) ++optind;
1302 }
1303 else { /* need an argument */
1304 if (*place) optarg = place; /* no white space */
1305 else if (nargc <= ++optind) { /* no arg */
1306 place = EMSG;
1307 tell(": option requires an argument -- ");
1308 }
1309 else optarg = nargv[optind]; /* white space */
1310 place = EMSG;
1311 ++optind;
1312 }
1313 return(optopt); /* dump back option letter */
1314}
1315
1316#endif
1317\f/*
1318** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
1319*/
1320
1321#ifdef NEEDVPRINTF
1322
1323#define MAXARG 16
1324
1325vfprintf(fp, fmt, ap)
1326 FILE * fp;
1327 char * fmt;
1328 char ** ap;
1329{
1330 char * bp[MAXARG];
1331 int i = 0;
1332
1333 while (*ap && i < MAXARG)
1334 bp[i++] = *ap++;
1335 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3],
1336 bp[4], bp[5], bp[6], bp[7],
1337 bp[8], bp[9], bp[10], bp[11],
1338 bp[12], bp[13], bp[14], bp[15]);
1339}
1340
1341vsprintf(s, fmt, ap)
1342 char * s;
1343 char * fmt;
1344 char ** ap;
1345{
1346 char * bp[MAXARG];
1347 int i = 0;
1348
1349 while (*ap && i < MAXARG)
1350 bp[i++] = *ap++;
1351 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3],
1352 bp[4], bp[5], bp[6], bp[7],
1353 bp[8], bp[9], bp[10], bp[11],
1354 bp[12], bp[13], bp[14], bp[15]);
1355}
1356
1357#endif
1358\f/*
1359** FREESPACE -- see how much free space is on the queue filesystem
6f14531a
RG
1360**
1361** Only implemented if you have statfs.
1362**
1363** Parameters:
d747e748
JH
1364** dir -- the directory in question.
1365** bsize -- a variable into which the filesystem
1366** block size is stored.
6f14531a
RG
1367**
1368** Returns:
d747e748
JH
1369** The number of bytes free on the queue filesystem.
1370** -1 if the statfs call fails.
1371**
1372** Side effects:
1373** Puts the filesystem block size into bsize.
6f14531a
RG
1374*/
1375
6f14531a
RG
1376#ifdef HASSTATFS
1377# undef HASUSTAT
1378#endif
1379
1380#if defined(HASUSTAT)
1381# include <ustat.h>
1382#endif
1383
1384#ifdef HASSTATFS
d747e748 1385# if defined(IRIX) || defined(apollo) || defined(_SCO_unix_) || defined(UMAXV) || defined(DGUX)
6f14531a
RG
1386# include <sys/statfs.h>
1387# else
d747e748 1388# if (defined(sun) && !defined(BSD)) || defined(__hpux) || defined(_CONVEX_SOURCE) || defined(NeXT) || defined(_AUX_SOURCE)
6f14531a
RG
1389# include <sys/vfs.h>
1390# else
1391# include <sys/mount.h>
1392# endif
1393# endif
1394#endif
1395
d747e748
JH
1396long
1397freespace(dir, bsize)
1398 char *dir;
1399 long *bsize;
6f14531a
RG
1400{
1401#if defined(HASSTATFS) || defined(HASUSTAT)
1402# if defined(HASUSTAT)
1403 struct ustat fs;
1404 struct stat statbuf;
1405# define FSBLOCKSIZE DEV_BSIZE
1406# define f_bavail f_tfree
1407# else
1408# if defined(ultrix)
1409 struct fs_data fs;
1410# define f_bavail fd_bfreen
1411# define FSBLOCKSIZE fs.fd_bsize
1412# else
1413 struct statfs fs;
1414# define FSBLOCKSIZE fs.f_bsize
d747e748
JH
1415# if defined(_SCO_unix_) || defined(IRIX)
1416# define f_bavail f_bfree
1417# endif
6f14531a
RG
1418# endif
1419# endif
1420 extern int errno;
1421
6f14531a 1422# if defined(HASUSTAT)
d747e748 1423 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
6f14531a 1424# else
d747e748
JH
1425# if defined(IRIX) || defined(apollo) || defined(UMAXV) || defined(DGUX)
1426 if (statfs(dir, &fs, sizeof fs, 0) == 0)
6f14531a
RG
1427# else
1428# if defined(ultrix)
d747e748 1429 if (statfs(dir, &fs) > 0)
6f14531a 1430# else
d747e748 1431 if (statfs(dir, &fs) == 0)
6f14531a
RG
1432# endif
1433# endif
1434# endif
d747e748
JH
1435 {
1436 if (bsize != NULL)
1437 *bsize = FSBLOCKSIZE;
1438 return (fs.f_bavail);
1439 }
1440#endif
1441 return (-1);
1442}
1443\f/*
1444** ENOUGHSPACE -- check to see if there is enough free space on the queue fs
1445**
1446** Only implemented if you have statfs.
1447**
1448** Parameters:
1449** msize -- the size to check against. If zero, we don't yet
1450** know how big the message will be, so just check for
1451** a "reasonable" amount.
1452**
1453** Returns:
1454** TRUE if there is enough space.
1455** FALSE otherwise.
1456*/
1457
1458bool
1459enoughspace(msize)
1460 long msize;
1461{
1462 long bfree, bsize;
1463
1464 if (MinBlocksFree <= 0 && msize <= 0)
1465 {
1466 if (tTd(4, 80))
1467 printf("enoughspace: no threshold\n");
1468 return TRUE;
1469 }
1470
1471 if ((bfree = freespace(QueueDir, &bsize)) >= 0)
6f14531a
RG
1472 {
1473 if (tTd(4, 80))
1474 printf("enoughspace: bavail=%ld, need=%ld\n",
d747e748 1475 bfree, msize);
6f14531a
RG
1476
1477 /* convert msize to block count */
d747e748 1478 msize = msize / bsize + 1;
6f14531a
RG
1479 if (MinBlocksFree >= 0)
1480 msize += MinBlocksFree;
1481
d747e748 1482 if (bfree < msize)
6f14531a
RG
1483 {
1484#ifdef LOG
1485 if (LogLevel > 0)
d747e748
JH
1486 syslog(LOG_ALERT,
1487 "%s: low on space (have %ld, %s needs %ld in %s)",
1488 CurEnv->e_id, bfree,
1489 CurHostName, msize, QueueDir);
6f14531a
RG
1490#endif
1491 return FALSE;
1492 }
1493 }
1494 else if (tTd(4, 80))
1495 printf("enoughspace failure: min=%ld, need=%ld: %s\n",
1496 MinBlocksFree, msize, errstring(errno));
6f14531a
RG
1497 return TRUE;
1498}
1499\f/*
1500** TRANSIENTERROR -- tell if an error code indicates a transient failure
1501**
1502** This looks at an errno value and tells if this is likely to
1503** go away if retried later.
1504**
1505** Parameters:
1506** err -- the errno code to classify.
1507**
1508** Returns:
1509** TRUE if this is probably transient.
1510** FALSE otherwise.
1511*/
1512
1513bool
1514transienterror(err)
1515 int err;
1516{
1517 switch (err)
1518 {
1519 case EIO: /* I/O error */
1520 case ENXIO: /* Device not configured */
1521 case EAGAIN: /* Resource temporarily unavailable */
1522 case ENOMEM: /* Cannot allocate memory */
1523 case ENODEV: /* Operation not supported by device */
1524 case ENFILE: /* Too many open files in system */
1525 case EMFILE: /* Too many open files */
1526 case ENOSPC: /* No space left on device */
1527#ifdef ETIMEDOUT
1528 case ETIMEDOUT: /* Connection timed out */
1529#endif
1530#ifdef ESTALE
1531 case ESTALE: /* Stale NFS file handle */
1532#endif
1533#ifdef ENETDOWN
1534 case ENETDOWN: /* Network is down */
1535#endif
1536#ifdef ENETUNREACH
1537 case ENETUNREACH: /* Network is unreachable */
1538#endif
1539#ifdef ENETRESET
1540 case ENETRESET: /* Network dropped connection on reset */
1541#endif
1542#ifdef ECONNABORTED
1543 case ECONNABORTED: /* Software caused connection abort */
1544#endif
1545#ifdef ECONNRESET
1546 case ECONNRESET: /* Connection reset by peer */
1547#endif
1548#ifdef ENOBUFS
1549 case ENOBUFS: /* No buffer space available */
1550#endif
1551#ifdef ESHUTDOWN
1552 case ESHUTDOWN: /* Can't send after socket shutdown */
1553#endif
1554#ifdef ECONNREFUSED
1555 case ECONNREFUSED: /* Connection refused */
1556#endif
1557#ifdef EHOSTDOWN
1558 case EHOSTDOWN: /* Host is down */
1559#endif
1560#ifdef EHOSTUNREACH
1561 case EHOSTUNREACH: /* No route to host */
1562#endif
1563#ifdef EDQUOT
1564 case EDQUOT: /* Disc quota exceeded */
1565#endif
1566#ifdef EPROCLIM
1567 case EPROCLIM: /* Too many processes */
1568#endif
1569#ifdef EUSERS
1570 case EUSERS: /* Too many users */
1571#endif
1572#ifdef EDEADLK
1573 case EDEADLK: /* Resource deadlock avoided */
1574#endif
1575#ifdef EISCONN
1576 case EISCONN: /* Socket already connected */
1577#endif
1578#ifdef EINPROGRESS
1579 case EINPROGRESS: /* Operation now in progress */
1580#endif
1581#ifdef EALREADY
1582 case EALREADY: /* Operation already in progress */
1583#endif
1584#ifdef EADDRINUSE
1585 case EADDRINUSE: /* Address already in use */
1586#endif
1587#ifdef EADDRNOTAVAIL
1588 case EADDRNOTAVAIL: /* Can't assign requested address */
1589#endif
d747e748 1590#if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
6f14531a
RG
1591 case ENOSR: /* Out of streams resources */
1592#endif
1593 return TRUE;
1594 }
1595
1596 /* nope, must be permanent */
1597 return FALSE;
1598}
1599\f/*
d747e748 1600** LOCKFILE -- lock a file using flock or (shudder) fcntl locking
6f14531a
RG
1601**
1602** Parameters:
1603** fd -- the file descriptor of the file.
1604** filename -- the file name (for error messages).
d747e748 1605** ext -- the filename extension.
6f14531a
RG
1606** type -- type of the lock. Bits can be:
1607** LOCK_EX -- exclusive lock.
1608** LOCK_NB -- non-blocking.
1609**
1610** Returns:
1611** TRUE if the lock was acquired.
1612** FALSE otherwise.
1613*/
1614
1615bool
d747e748 1616lockfile(fd, filename, ext, type)
6f14531a
RG
1617 int fd;
1618 char *filename;
d747e748 1619 char *ext;
6f14531a
RG
1620 int type;
1621{
d747e748 1622# ifndef HASFLOCK
6f14531a
RG
1623 int action;
1624 struct flock lfd;
1625
d747e748
JH
1626 if (ext == NULL)
1627 ext = "";
1628
1629 bzero(&lfd, sizeof lfd);
6f14531a
RG
1630 if (bitset(LOCK_UN, type))
1631 lfd.l_type = F_UNLCK;
1632 else if (bitset(LOCK_EX, type))
1633 lfd.l_type = F_WRLCK;
1634 else
1635 lfd.l_type = F_RDLCK;
1636
1637 if (bitset(LOCK_NB, type))
1638 action = F_SETLK;
1639 else
1640 action = F_SETLKW;
1641
d747e748
JH
1642 if (tTd(55, 60))
1643 printf("lockfile(%s%s, action=%d, type=%d): ",
1644 filename, ext, action, lfd.l_type);
6f14531a
RG
1645
1646 if (fcntl(fd, action, &lfd) >= 0)
d747e748
JH
1647 {
1648 if (tTd(55, 60))
1649 printf("SUCCESS\n");
6f14531a 1650 return TRUE;
d747e748
JH
1651 }
1652
1653 if (tTd(55, 60))
1654 printf("(%s) ", errstring(errno));
1655
1656 /*
1657 ** On SunOS, if you are testing using -oQ/tmp/mqueue or
1658 ** -oA/tmp/aliases or anything like that, and /tmp is mounted
1659 ** as type "tmp" (that is, served from swap space), the
1660 ** previous fcntl will fail with "Invalid argument" errors.
1661 ** Since this is fairly common during testing, we will assume
1662 ** that this indicates that the lock is successfully grabbed.
1663 */
1664
1665 if (errno == EINVAL)
1666 {
1667 if (tTd(55, 60))
1668 printf("SUCCESS\n");
1669 return TRUE;
1670 }
6f14531a
RG
1671
1672 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN))
d747e748
JH
1673 {
1674 int omode = -1;
1675# ifdef F_GETFL
1676 int oerrno = errno;
1677
1678 (void) fcntl(fd, F_GETFL, &omode);
1679 errno = oerrno;
1680# endif
1681 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
1682 filename, ext, fd, type, omode, geteuid());
1683 }
6f14531a 1684# else
d747e748
JH
1685 if (ext == NULL)
1686 ext = "";
1687
1688 if (tTd(55, 60))
1689 printf("lockfile(%s%s, type=%o): ", filename, ext, type);
1690
6f14531a 1691 if (flock(fd, type) >= 0)
d747e748
JH
1692 {
1693 if (tTd(55, 60))
1694 printf("SUCCESS\n");
6f14531a 1695 return TRUE;
d747e748
JH
1696 }
1697
1698 if (tTd(55, 60))
1699 printf("(%s) ", errstring(errno));
6f14531a
RG
1700
1701 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK)
d747e748
JH
1702 {
1703 int omode = -1;
1704# ifdef F_GETFL
1705 int oerrno = errno;
1706
1707 (void) fcntl(fd, F_GETFL, &omode);
1708 errno = oerrno;
1709# endif
1710 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
1711 filename, ext, fd, type, omode, geteuid());
1712 }
6f14531a 1713# endif
d747e748
JH
1714 if (tTd(55, 60))
1715 printf("FAIL\n");
6f14531a 1716 return FALSE;
15637ed4 1717}
d747e748
JH
1718\f/*
1719** GETCFNAME -- return the name of the .cf file.
1720**
1721** Some systems (e.g., NeXT) determine this dynamically.
1722*/
1723
1724char *
1725getcfname()
1726{
1727 if (ConfFile != NULL)
1728 return ConfFile;
1729 return _PATH_SENDMAILCF;
1730}
1731\f/*
1732** SETVENDOR -- process vendor code from V configuration line
1733**
1734** Parameters:
1735** vendor -- string representation of vendor.
1736**
1737** Returns:
1738** TRUE -- if ok.
1739** FALSE -- if vendor code could not be processed.
1740*/
1741
1742bool
1743setvendor(vendor)
1744 char *vendor;
1745{
1746 return (strcasecmp(vendor, "Berkeley") == 0);
1747}