Commit | Line | Data |
---|---|---|
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 | 36 | static 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 | ||
79 | struct 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 | 130 | char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ |
15637ed4 RG |
131 | |
132 | ||
133 | ||
134 | /* | |
6f14531a | 135 | ** Privacy values |
15637ed4 RG |
136 | */ |
137 | ||
6f14531a RG |
138 | struct 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 | ||
159 | int 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 | |
169 | bool BrokenSmtpPeers = TRUE; /* set if you have broken SMTP peers */ | |
170 | #else | |
171 | bool BrokenSmtpPeers = FALSE; /* set if you have broken SMTP peers */ | |
172 | #endif | |
173 | #ifdef NOLOOPBACKCHECK | |
174 | bool CheckLoopBack = FALSE; /* set to check HELO loopback */ | |
175 | #else | |
176 | bool 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 | ||
198 | setdefaults(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 | ||
234 | setdefuser() | |
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 | ||
249 | bool | |
250 | host_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 |
281 | setupmailers() |
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 | ||
316 | setupmaps() | |
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 | ||
386 | char * | |
387 | username() | |
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 |
449 | char * |
450 | ttypath() | |
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 | 504 | checkcompat(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 | ||
538 | sigfunc_t | |
539 | setsignal(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 | ||
568 | holdsigs() | |
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 | ||
586 | rlsesigs() | |
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 | ||
600 | init_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 |
655 | struct 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 | |
680 | getla() | |
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 | ||
763 | int 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 |
775 | getla() |
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 | ||
800 | getla() | |
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 | ||
824 | getla() | |
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 | ||
852 | bool | |
6f14531a | 853 | shouldqueue(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 | ||
878 | bool | |
879 | refuseconnections() | |
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__ |
925 | setproctitle(char *fmt, ...) | |
926 | #else | |
927 | setproctitle(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 |
990 | void |
991 | reapchild() | |
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 | |
1048 | void | |
1049 | unsetenv(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 | |
1087 | int | |
3a363396 | 1088 | getdtsize() |
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 | ||
1113 | int | |
1114 | uname(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 | ||
1177 | initgroups(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 |
1191 | pid_t |
1192 | setsid __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 | ||
1223 | long | |
1224 | dgux_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) | |
1253 | static 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 | */ | |
1261 | int opterr = 1, /* if error message should be printed */ | |
1262 | optind = 1, /* index into parent argv vector */ | |
1263 | optopt; /* character checked for validity */ | |
1264 | char *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 | ||
1271 | getopt(nargc,nargv,ostr) | |
1272 | int nargc; | |
1273 | char **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 | ||
1325 | vfprintf(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 | ||
1341 | vsprintf(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 |
1396 | long |
1397 | freespace(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 | ||
1458 | bool | |
1459 | enoughspace(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 | ||
1513 | bool | |
1514 | transienterror(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 | ||
1615 | bool | |
d747e748 | 1616 | lockfile(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 | ||
1724 | char * | |
1725 | getcfname() | |
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 | ||
1742 | bool | |
1743 | setvendor(vendor) | |
1744 | char *vendor; | |
1745 | { | |
1746 | return (strcasecmp(vendor, "Berkeley") == 0); | |
1747 | } |