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