1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)conf.c 6.34 (Berkeley) 03/13/93"; 11 #endif /* not lint */ 12 13 # include <sys/ioctl.h> 14 # include <sys/param.h> 15 # include <signal.h> 16 # include <pwd.h> 17 # include "sendmail.h" 18 # include "pathnames.h" 19 20 /* 21 ** CONF.C -- Sendmail Configuration Tables. 22 ** 23 ** Defines the configuration of this installation. 24 ** 25 ** Configuration Variables: 26 ** HdrInfo -- a table describing well-known header fields. 27 ** Each entry has the field name and some flags, 28 ** which are described in sendmail.h. 29 ** 30 ** Notes: 31 ** I have tried to put almost all the reasonable 32 ** configuration information into the configuration 33 ** file read at runtime. My intent is that anything 34 ** here is a function of the version of UNIX you 35 ** are running, or is really static -- for example 36 ** the headers are a superset of widely used 37 ** protocols. If you find yourself playing with 38 ** this file too much, you may be making a mistake! 39 */ 40 41 42 43 44 /* 45 ** Header info table 46 ** Final (null) entry contains the flags used for any other field. 47 ** 48 ** Not all of these are actually handled specially by sendmail 49 ** at this time. They are included as placeholders, to let 50 ** you know that "someday" I intend to have sendmail do 51 ** something with them. 52 */ 53 54 struct hdrinfo HdrInfo[] = 55 { 56 /* originator fields, most to least significant */ 57 "resent-sender", H_FROM|H_RESENT, 58 "resent-from", H_FROM|H_RESENT, 59 "resent-reply-to", H_FROM|H_RESENT, 60 "sender", H_FROM, 61 "from", H_FROM, 62 "reply-to", H_FROM, 63 "full-name", H_ACHECK, 64 "return-receipt-to", H_FROM /* |H_RECEIPTTO */, 65 "errors-to", H_FROM|H_ERRORSTO, 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 /* message identification and control */ 75 "message-id", 0, 76 "resent-message-id", H_RESENT, 77 "message", H_EOH, 78 "text", H_EOH, 79 /* date fields */ 80 "date", 0, 81 "resent-date", H_RESENT, 82 /* trace fields */ 83 "received", H_TRACE|H_FORCE, 84 "via", H_TRACE|H_FORCE, 85 "mail-from", H_TRACE|H_FORCE, 86 87 NULL, 0, 88 }; 89 90 91 92 /* 93 ** Location of system files/databases/etc. 94 */ 95 96 char *ConfFile = _PATH_SENDMAILCF; /* runtime configuration */ 97 char *FreezeFile = _PATH_SENDMAILFC; /* frozen version of above */ 98 char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ 99 100 101 102 /* 103 ** Privacy values 104 */ 105 106 struct prival PrivacyValues[] = 107 { 108 "public", PRIV_PUBLIC, 109 "needmailhelo", PRIV_NEEDMAILHELO, 110 "needexpnhelo", PRIV_NEEDEXPNHELO, 111 "needvrfyhelo", PRIV_NEEDVRFYHELO, 112 "noexpn", PRIV_NOEXPN, 113 "novrfy", PRIV_NOVRFY, 114 "restrictmailq", PRIV_RESTRMAILQ, 115 "goaway", PRIV_GOAWAY, 116 NULL, PRIV_PUBLIC, 117 }; 118 119 120 121 /* 122 ** Miscellaneous stuff. 123 */ 124 125 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 126 /* 127 ** SETDEFAULTS -- set default values 128 ** 129 ** Because of the way freezing is done, these must be initialized 130 ** using direct code. 131 ** 132 ** Parameters: 133 ** none. 134 ** 135 ** Returns: 136 ** none. 137 ** 138 ** Side Effects: 139 ** Initializes a bunch of global variables to their 140 ** default values. 141 */ 142 143 setdefaults() 144 { 145 SpaceSub = ' '; /* option B */ 146 QueueLA = 8; /* option x */ 147 RefuseLA = 12; /* option X */ 148 WkRecipFact = 30000L; /* option y */ 149 WkClassFact = 1800L; /* option z */ 150 WkTimeFact = 90000L; /* option Z */ 151 QueueFactor = WkRecipFact * 20; /* option q */ 152 FileMode = (getuid() != geteuid()) ? 0644 : 0600; 153 /* option F */ 154 DefUid = 1; /* option u */ 155 DefGid = 1; /* option g */ 156 CheckpointInterval = 10; /* option C */ 157 MaxHopCount = 25; /* option h */ 158 SendMode = SM_FORK; /* option d */ 159 ErrorMode = EM_PRINT; /* option e */ 160 EightBit = FALSE; /* option 8 */ 161 MaxMciCache = 1; /* option k */ 162 MciCacheTimeout = 300; /* option K */ 163 LogLevel = 9; /* option L */ 164 settimeouts(NULL); /* option r */ 165 TimeOut = 5 * 24 * 60 * 60; /* option T */ 166 setdefuser(); 167 setupmaps(); 168 setupmailers(); 169 } 170 171 172 /* 173 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 174 */ 175 176 setdefuser() 177 { 178 struct passwd *defpwent; 179 static char defuserbuf[40]; 180 181 DefUser = defuserbuf; 182 if ((defpwent = getpwuid(DefUid)) != NULL) 183 strcpy(defuserbuf, defpwent->pw_name); 184 else 185 strcpy(defuserbuf, "nobody"); 186 } 187 /* 188 ** SETUPMAPS -- set up map classes 189 ** 190 ** Since these are compiled in, they cannot be in the config file. 191 ** 192 */ 193 194 setupmaps() 195 { 196 register STAB *s; 197 extern bool host_map_init(); 198 extern char *maphostname(); 199 200 /* set up host name lookup map */ 201 s = stab("host", ST_MAPCLASS, ST_ENTER); 202 s->s_mapclass.map_init = host_map_init; 203 s->s_mapclass.map_lookup = maphostname; 204 205 /* 206 ** Set up other map classes. 207 */ 208 209 # ifdef DBM_MAP 210 /* dbm file access */ 211 { 212 extern bool dbm_map_init(); 213 extern char *dbm_map_lookup(); 214 215 s = stab("dbm", ST_MAPCLASS, ST_ENTER); 216 s->s_mapclass.map_init = dbm_map_init; 217 s->s_mapclass.map_lookup = dbm_map_lookup; 218 } 219 # endif 220 221 # ifdef BTREE_MAP 222 /* new database file access -- btree files */ 223 { 224 extern bool bt_map_init(); 225 extern char *db_map_lookup(); 226 227 s = stab("btree", ST_MAPCLASS, ST_ENTER); 228 s->s_mapclass.map_init = bt_map_init; 229 s->s_mapclass.map_lookup = db_map_lookup; 230 } 231 # endif 232 233 # ifdef HASH_MAP 234 /* new database file access -- hash files */ 235 { 236 extern bool hash_map_init(); 237 extern char *db_map_lookup(); 238 239 s = stab("hash", ST_MAPCLASS, ST_ENTER); 240 s->s_mapclass.map_init = hash_map_init; 241 s->s_mapclass.map_lookup = db_map_lookup; 242 } 243 # endif 244 245 # ifdef NIS_MAP 246 /* NIS map access */ 247 { 248 extern bool nis_map_init(); 249 extern char *nis_map_lookup(); 250 251 s = stab("nis", ST_MAPCLASS, ST_ENTER); 252 s->s_mapclass.map_init = nis_map_init; 253 s->s_mapclass.map_lookup = nis_map_lookup; 254 } 255 # endif 256 257 # ifdef USERDB_MAP 258 /* user database */ 259 { 260 extern bool udb_map_init(); 261 extern char *udb_map_lookup(); 262 263 s = stab("udb", ST_MAPCLASS, ST_ENTER); 264 s->s_mapclass.map_init = udb_map_init; 265 s->s_mapclass.map_lookup = udb_map_lookup; 266 } 267 # endif 268 } 269 /* 270 ** HOST_MAP_INIT -- initialize host class structures 271 */ 272 273 bool 274 host_map_init(map, mapname, args) 275 MAP *map; 276 char *mapname; 277 char *args; 278 { 279 register char *p = args; 280 281 for (;;) 282 { 283 while (isascii(*p) && isspace(*p)) 284 p++; 285 if (*p != '-') 286 break; 287 switch (*++p) 288 { 289 case 'a': 290 map->map_app = ++p; 291 break; 292 } 293 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 294 p++; 295 if (*p != '\0') 296 *p++ = '\0'; 297 } 298 if (map->map_app != NULL) 299 map->map_app = newstr(map->map_app); 300 return TRUE; 301 } 302 /* 303 ** SETUPMAILERS -- initialize default mailers 304 */ 305 306 setupmailers() 307 { 308 char buf[100]; 309 310 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 311 makemailer(buf); 312 313 strcpy(buf, "*file*, P=/dev/null, F=lsDEu, A=FILE"); 314 makemailer(buf); 315 316 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 317 makemailer(buf); 318 } 319 /* 320 ** GETRUID -- get real user id (V7) 321 */ 322 323 getruid() 324 { 325 if (OpMode == MD_DAEMON) 326 return (RealUid); 327 else 328 return (getuid()); 329 } 330 331 332 /* 333 ** GETRGID -- get real group id (V7). 334 */ 335 336 getrgid() 337 { 338 if (OpMode == MD_DAEMON) 339 return (RealGid); 340 else 341 return (getgid()); 342 } 343 /* 344 ** USERNAME -- return the user id of the logged in user. 345 ** 346 ** Parameters: 347 ** none. 348 ** 349 ** Returns: 350 ** The login name of the logged in user. 351 ** 352 ** Side Effects: 353 ** none. 354 ** 355 ** Notes: 356 ** The return value is statically allocated. 357 */ 358 359 char * 360 username() 361 { 362 static char *myname = NULL; 363 extern char *getlogin(); 364 register struct passwd *pw; 365 366 /* cache the result */ 367 if (myname == NULL) 368 { 369 myname = getlogin(); 370 if (myname == NULL || myname[0] == '\0') 371 { 372 373 pw = getpwuid(getruid()); 374 if (pw != NULL) 375 myname = newstr(pw->pw_name); 376 } 377 else 378 { 379 380 myname = newstr(myname); 381 if ((pw = getpwnam(myname)) == NULL || 382 getuid() != pw->pw_uid) 383 { 384 pw = getpwuid(getuid()); 385 if (pw != NULL) 386 myname = newstr(pw->pw_name); 387 } 388 } 389 if (myname == NULL || myname[0] == '\0') 390 { 391 syserr("554 Who are you?"); 392 myname = "postmaster"; 393 } 394 } 395 396 return (myname); 397 } 398 /* 399 ** TTYPATH -- Get the path of the user's tty 400 ** 401 ** Returns the pathname of the user's tty. Returns NULL if 402 ** the user is not logged in or if s/he has write permission 403 ** denied. 404 ** 405 ** Parameters: 406 ** none 407 ** 408 ** Returns: 409 ** pathname of the user's tty. 410 ** NULL if not logged in or write permission denied. 411 ** 412 ** Side Effects: 413 ** none. 414 ** 415 ** WARNING: 416 ** Return value is in a local buffer. 417 ** 418 ** Called By: 419 ** savemail 420 */ 421 422 # include <sys/stat.h> 423 424 char * 425 ttypath() 426 { 427 struct stat stbuf; 428 register char *pathn; 429 extern char *ttyname(); 430 extern char *getlogin(); 431 432 /* compute the pathname of the controlling tty */ 433 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 434 (pathn = ttyname(0)) == NULL) 435 { 436 errno = 0; 437 return (NULL); 438 } 439 440 /* see if we have write permission */ 441 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 442 { 443 errno = 0; 444 return (NULL); 445 } 446 447 /* see if the user is logged in */ 448 if (getlogin() == NULL) 449 return (NULL); 450 451 /* looks good */ 452 return (pathn); 453 } 454 /* 455 ** CHECKCOMPAT -- check for From and To person compatible. 456 ** 457 ** This routine can be supplied on a per-installation basis 458 ** to determine whether a person is allowed to send a message. 459 ** This allows restriction of certain types of internet 460 ** forwarding or registration of users. 461 ** 462 ** If the hosts are found to be incompatible, an error 463 ** message should be given using "usrerr" and 0 should 464 ** be returned. 465 ** 466 ** 'NoReturn' can be set to suppress the return-to-sender 467 ** function; this should be done on huge messages. 468 ** 469 ** Parameters: 470 ** to -- the person being sent to. 471 ** 472 ** Returns: 473 ** an exit status 474 ** 475 ** Side Effects: 476 ** none (unless you include the usrerr stuff) 477 */ 478 479 checkcompat(to, e) 480 register ADDRESS *to; 481 register ENVELOPE *e; 482 { 483 # ifdef lint 484 if (to == NULL) 485 to++; 486 # endif lint 487 # ifdef EXAMPLE_CODE 488 /* this code is intended as an example only */ 489 register STAB *s; 490 491 s = stab("arpa", ST_MAILER, ST_FIND); 492 if (s != NULL && e->e_from.q_mailer != LocalMailer && 493 to->q_mailer == s->s_mailer) 494 { 495 usrerr("553 No ARPA mail through this machine: see your system administration"); 496 /* NoReturn = TRUE; to supress return copy */ 497 return (EX_UNAVAILABLE); 498 } 499 # endif /* EXAMPLE_CODE */ 500 return (EX_OK); 501 } 502 /* 503 ** HOLDSIGS -- arrange to hold all signals 504 ** 505 ** Parameters: 506 ** none. 507 ** 508 ** Returns: 509 ** none. 510 ** 511 ** Side Effects: 512 ** Arranges that signals are held. 513 */ 514 515 holdsigs() 516 { 517 } 518 /* 519 ** RLSESIGS -- arrange to release all signals 520 ** 521 ** This undoes the effect of holdsigs. 522 ** 523 ** Parameters: 524 ** none. 525 ** 526 ** Returns: 527 ** none. 528 ** 529 ** Side Effects: 530 ** Arranges that signals are released. 531 */ 532 533 rlsesigs() 534 { 535 } 536 /* 537 ** GETLA -- get the current load average 538 ** 539 ** This code stolen from la.c. 540 ** 541 ** Parameters: 542 ** none. 543 ** 544 ** Returns: 545 ** The current load average as an integer. 546 ** 547 ** Side Effects: 548 ** none. 549 */ 550 551 /* try to guess what style of load average we have */ 552 #define LA_ZERO 1 /* always return load average as zero */ 553 #define LA_INT 2 /* read kmem for avenrun; interpret as int */ 554 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 555 #define LA_SUBR 4 /* call getloadavg */ 556 557 #ifndef LA_TYPE 558 # if defined(sun) 559 # define LA_TYPE LA_INT 560 # endif 561 # if defined(mips) || defined(__alpha) 562 /* Ultrix or OSF/1 or RISC/os */ 563 # define LA_TYPE LA_INT 564 # define LA_AVENRUN "avenrun" 565 # endif 566 # if defined(hpux) 567 # define LA_TYPE LA_FLOAT 568 # endif 569 570 # ifndef LA_TYPE 571 # if defined(SYSTEM5) 572 # define LA_TYPE LA_INT 573 # define LA_AVENRUN "avenrun" 574 # else 575 # if defined(BSD) 576 # define LA_TYPE LA_SUBR 577 # else 578 # define LA_TYPE LA_ZERO 579 # endif 580 # endif 581 # endif 582 #endif 583 584 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) 585 586 #include <nlist.h> 587 #include <fcntl.h> 588 589 #ifndef LA_AVENRUN 590 #define LA_AVENRUN "_avenrun" 591 #endif 592 593 /* _PATH_UNIX should be defined in <paths.h> */ 594 #ifndef _PATH_UNIX 595 # if defined(hpux) 596 # define _PATH_UNIX "/hp-ux" 597 # endif 598 # if defined(mips) && !defined(ultrix) 599 /* powerful RISC/os */ 600 # define _PATH_UNIX "/unix" 601 # endif 602 # if defined(SYSTEM5) 603 # ifndef _PATH_UNIX 604 # define _PATH_UNIX "/unix" 605 # endif 606 # endif 607 # ifndef _PATH_UNIX 608 # define _PATH_UNIX "/vmunix" 609 # endif 610 #endif 611 612 struct nlist Nl[] = 613 { 614 { LA_AVENRUN }, 615 #define X_AVENRUN 0 616 { 0 }, 617 }; 618 619 #if defined(unixpc) 620 # define FSHIFT 5 621 #endif 622 623 #if defined(__alpha) 624 # define FSHIFT 10 625 #endif 626 627 #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 628 # define FSHIFT 8 629 #endif 630 #if (LA_TYPE == LA_INT) && !defined(FSCALE) 631 # define FSCALE (1 << FSHIFT) 632 #endif 633 634 getla() 635 { 636 static int kmem = -1; 637 #if LA_TYPE == LA_INT 638 long avenrun[3]; 639 #else 640 double avenrun[3]; 641 #endif 642 extern off_t lseek(); 643 extern char *errstring(); 644 extern int errno; 645 646 if (kmem < 0) 647 { 648 kmem = open("/dev/kmem", 0, 0); 649 if (kmem < 0) 650 { 651 if (tTd(3, 1)) 652 printf("getla: open(/dev/kmem): %s\n", 653 errstring(errno)); 654 return (-1); 655 } 656 (void) fcntl(kmem, F_SETFD, 1); 657 if (nlist(_PATH_UNIX, Nl) < 0) 658 { 659 if (tTd(3, 1)) 660 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 661 errstring(errno)); 662 return (-1); 663 } 664 } 665 if (tTd(3, 20)) 666 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 667 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 668 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 669 { 670 /* thank you Ian */ 671 if (tTd(3, 1)) 672 printf("getla: lseek or read: %s\n", errstring(errno)); 673 return (-1); 674 } 675 #if LA_TYPE == LA_INT 676 if (tTd(3, 5)) 677 { 678 printf("getla: avenrun = %d", avenrun[0]); 679 if (tTd(3, 15)) 680 printf(", %d, %d", avenrun[1], avenrun[2]); 681 printf("\n"); 682 } 683 if (tTd(3, 1)) 684 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 685 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 686 #else 687 if (tTd(3, 5)) 688 { 689 printf("getla: avenrun = %g", avenrun[0]); 690 if (tTd(3, 15)) 691 printf(", %g, %g", avenrun[1], avenrun[2]); 692 printf("\n"); 693 } 694 if (tTd(3, 1)) 695 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 696 return ((int) (avenrun[0] + 0.5)); 697 #endif 698 } 699 700 #else 701 #if LA_TYPE == LA_SUBR 702 703 getla() 704 { 705 double avenrun[3]; 706 707 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 708 { 709 if (tTd(3, 1)) 710 perror("getla: getloadavg failed:"); 711 return (-1); 712 } 713 if (tTd(3, 1)) 714 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 715 return ((int) (avenrun[0] + 0.5)); 716 } 717 718 #else 719 720 getla() 721 { 722 if (tTd(3, 1)) 723 printf("getla: ZERO\n"); 724 return (0); 725 } 726 727 #endif 728 #endif 729 /* 730 ** SHOULDQUEUE -- should this message be queued or sent? 731 ** 732 ** Compares the message cost to the load average to decide. 733 ** 734 ** Parameters: 735 ** pri -- the priority of the message in question. 736 ** ctime -- the message creation time. 737 ** 738 ** Returns: 739 ** TRUE -- if this message should be queued up for the 740 ** time being. 741 ** FALSE -- if the load is low enough to send this message. 742 ** 743 ** Side Effects: 744 ** none. 745 */ 746 747 bool 748 shouldqueue(pri, ctime) 749 long pri; 750 time_t ctime; 751 { 752 if (CurrentLA < QueueLA) 753 return (FALSE); 754 if (CurrentLA >= RefuseLA) 755 return (TRUE); 756 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 757 } 758 /* 759 ** REFUSECONNECTIONS -- decide if connections should be refused 760 ** 761 ** Parameters: 762 ** none. 763 ** 764 ** Returns: 765 ** TRUE if incoming SMTP connections should be refused 766 ** (for now). 767 ** FALSE if we should accept new work. 768 ** 769 ** Side Effects: 770 ** none. 771 */ 772 773 bool 774 refuseconnections() 775 { 776 /* this is probably too simplistic */ 777 return (CurrentLA >= RefuseLA); 778 } 779 /* 780 ** SETPROCTITLE -- set process title for ps 781 ** 782 ** Parameters: 783 ** fmt -- a printf style format string. If NULL, the first 784 ** parameter is a literal proctitle previously 785 ** returned by getproctitle. 786 ** va_alist -- possible parameters to fmt. 787 ** 788 ** Returns: 789 ** none. 790 ** 791 ** Side Effects: 792 ** Clobbers argv of our main procedure so ps(1) will 793 ** display the title. 794 */ 795 796 char ProcTitleBuf[MAXLINE]; 797 798 /*VARARGS1*/ 799 #ifdef __STDC__ 800 setproctitle(char *fmt, ...) 801 #else 802 setproctitle(fmt, va_alist) 803 char *fmt; 804 va_dcl 805 #endif 806 { 807 # ifdef SETPROCTITLE 808 register char *p; 809 register int i; 810 VA_LOCAL_DECL 811 extern char **Argv; 812 extern char *LastArgv; 813 814 VA_START(fmt); 815 if (fmt == NULL) 816 { 817 /* restore old proctitle */ 818 (void) strcpy(ProcTitleBuf, va_arg(ap, char *)); 819 } 820 else 821 { 822 p = ProcTitleBuf; 823 824 /* print sendmail: heading for grep */ 825 (void) strcpy(p, "sendmail: "); 826 p += strlen(p); 827 828 /* print the argument string */ 829 (void) vsprintf(p, fmt, ap); 830 } 831 VA_END; 832 833 i = strlen(ProcTitleBuf); 834 if (i > LastArgv - Argv[0] - 2) 835 { 836 i = LastArgv - Argv[0] - 2; 837 ProcTitleBuf[i] = '\0'; 838 } 839 (void) strcpy(Argv[0], ProcTitleBuf); 840 p = &Argv[0][i]; 841 while (p < LastArgv) 842 *p++ = ' '; 843 # endif /* SETPROCTITLE */ 844 } 845 /* 846 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 847 ** 848 ** Parameters: 849 ** none. 850 ** 851 ** Returns: 852 ** none. 853 ** 854 ** Side Effects: 855 ** Picks up extant zombies. 856 */ 857 858 # include <sys/wait.h> 859 860 void 861 reapchild() 862 { 863 # ifdef WNOHANG 864 union wait status; 865 866 while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 867 continue; 868 # else /* WNOHANG */ 869 auto int status; 870 871 while (wait((int *)&status) > 0) 872 continue; 873 # endif /* WNOHANG */ 874 # ifdef SYSTEM5 875 (void) signal(SIGCHLD, reapchild); 876 # endif 877 } 878 /* 879 ** UNSETENV -- remove a variable from the environment 880 ** 881 ** Not needed on newer systems. 882 ** 883 ** Parameters: 884 ** name -- the string name of the environment variable to be 885 ** deleted from the current environment. 886 ** 887 ** Returns: 888 ** none. 889 ** 890 ** Globals: 891 ** environ -- a pointer to the current environment. 892 ** 893 ** Side Effects: 894 ** Modifies environ. 895 */ 896 897 #ifdef UNSETENV 898 899 void 900 unsetenv(name) 901 char *name; 902 { 903 extern char **environ; 904 register char **pp; 905 int len = strlen(name); 906 907 for (pp = environ; *pp != NULL; pp++) 908 { 909 if (strncmp(name, *pp, len) == 0 && 910 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 911 break; 912 } 913 914 for (; *pp != NULL; pp++) 915 *pp = pp[1]; 916 } 917 918 #endif /* UNSETENV */ 919 /* 920 ** GETDTABLESIZE -- return number of file descriptors 921 ** 922 ** Only on non-BSD systems 923 ** 924 ** Parameters: 925 ** none 926 ** 927 ** Returns: 928 ** size of file descriptor table 929 ** 930 ** Side Effects: 931 ** none 932 */ 933 934 #ifdef SYSTEM5 935 936 int 937 getdtablesize() 938 { 939 return NOFILE; 940 } 941 942 #endif 943 /* 944 ** UNAME -- get the UUCP name of this system. 945 */ 946 947 #ifndef HASUNAME 948 949 int 950 uname(name) 951 struct utsname *name; 952 { 953 FILE *file; 954 char *n; 955 956 name->nodename[0] = '\0'; 957 958 /* try /etc/whoami -- one line with the node name */ 959 if ((file = fopen("/etc/whoami", "r")) != NULL) 960 { 961 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 962 (void) fclose(file); 963 n = strchr(name->nodename, '\n'); 964 if (n != NULL) 965 *n = '\0'; 966 if (name->nodename[0] != '\0') 967 return (0); 968 } 969 970 /* try /usr/include/whoami.h -- has a #define somewhere */ 971 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 972 { 973 char buf[MAXLINE]; 974 975 while (fgets(buf, MAXLINE, file) != NULL) 976 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 977 NODE_LENGTH, name->nodename) > 0) 978 break; 979 (void) fclose(file); 980 if (name->nodename[0] != '\0') 981 return (0); 982 } 983 984 #ifdef TRUST_POPEN 985 /* 986 ** Popen is known to have security holes. 987 */ 988 989 /* try uuname -l to return local name */ 990 if ((file = popen("uuname -l", "r")) != NULL) 991 { 992 (void) fgets(name, NODE_LENGTH + 1, file); 993 (void) pclose(file); 994 n = strchr(name, '\n'); 995 if (n != NULL) 996 *n = '\0'; 997 if (name->nodename[0] != '\0') 998 return (0); 999 } 1000 #endif 1001 1002 return (-1); 1003 } 1004 #endif /* HASUNAME */ 1005 /* 1006 ** INITGROUPS -- initialize groups 1007 ** 1008 ** Stub implementation for System V style systems 1009 */ 1010 1011 #ifndef HASINITGROUPS 1012 # if !defined(SYSTEM5) || defined(hpux) 1013 # define HASINITGROUPS 1014 # endif 1015 #endif 1016 1017 #ifndef HASINITGROUPS 1018 1019 initgroups(name, basegid) 1020 char *name; 1021 int basegid; 1022 { 1023 return 0; 1024 } 1025 1026 #endif 1027 /* 1028 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1029 ** 1030 ** Only implemented if you have statfs. 1031 ** 1032 ** Parameters: 1033 ** msize -- the size to check against. If zero, we don't yet 1034 ** know how big the message will be, so just check for 1035 ** a "reasonable" amount. 1036 ** 1037 ** Returns: 1038 ** TRUE if there is enough space. 1039 ** FALSE otherwise. 1040 */ 1041 1042 #ifndef HASSTATFS 1043 # if defined(BSD4_4) || defined(__osf__) 1044 # define HASSTATFS 1045 # endif 1046 #endif 1047 1048 #ifdef HASSTATFS 1049 # undef HASUSTAT 1050 #endif 1051 1052 #if defined(HASUSTAT) 1053 # include <sys/stat.h> 1054 # include <ustat.h> 1055 #endif 1056 1057 #ifdef HASSTATFS 1058 # if defined(sgi) || defined(apollo) 1059 # include <sys/statfs.h> 1060 # else 1061 # if defined(sun) || defined(hpux) 1062 # include <sys/vfs.h> 1063 # else 1064 # include <sys/mount.h> 1065 # endif 1066 # endif 1067 #endif 1068 1069 bool 1070 enoughspace(msize) 1071 long msize; 1072 { 1073 #if defined(HASSTATFS) || defined(HASUSTAT) 1074 # if defined(HASUSTAT) 1075 struct ustat fs; 1076 struct stat statbuf; 1077 # define FSBLOCKSIZE DEV_BSIZE 1078 # define f_bavail f_tfree 1079 # else 1080 # if defined(ultrix) 1081 struct fs_data fs; 1082 # define f_bavail fd_bfreen 1083 # define FSBLOCKSIZE fs.fd_bsize 1084 # else 1085 struct statfs fs; 1086 # define FSBLOCKSIZE fs.f_bsize 1087 # endif 1088 # endif 1089 long blocksneeded; 1090 extern int errno; 1091 extern char *errstring(); 1092 1093 if (MinBlocksFree <= 0 && msize <= 0) 1094 { 1095 if (tTd(4, 80)) 1096 printf("enoughspace: no threshold\n"); 1097 return TRUE; 1098 } 1099 1100 # if defined(HASUSTAT) 1101 if (stat(QueueDir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1102 # else 1103 # if defined(sgi) || defined(apollo) 1104 if (statfs(QueueDir, &fs, sizeof fs, 0) == 0) 1105 # else 1106 # if defined(ultrix) 1107 if (statfs(QueueDir, &fs) > 0) 1108 # else 1109 if (statfs(QueueDir, &fs) == 0) 1110 # endif 1111 # endif 1112 # endif 1113 { 1114 if (tTd(4, 80)) 1115 printf("enoughspace: bavail=%ld, need=%ld\n", 1116 fs.f_bavail, msize); 1117 1118 /* convert msize to block count */ 1119 msize = msize / FSBLOCKSIZE + 1; 1120 if (MinBlocksFree >= 0) 1121 msize += MinBlocksFree; 1122 1123 if (fs.f_bavail < msize) 1124 { 1125 #ifdef LOG 1126 if (LogLevel > 0) 1127 syslog(LOG_ALERT, "%s: low on space (have %ld, need %ld)", 1128 QueueDir, fs.f_bavail, msize); 1129 #endif 1130 return FALSE; 1131 } 1132 } 1133 else if (tTd(4, 80)) 1134 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1135 MinBlocksFree, msize, errstring(errno)); 1136 #endif 1137 return TRUE; 1138 } 1139 /* 1140 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1141 ** 1142 ** This looks at an errno value and tells if this is likely to 1143 ** go away if retried later. 1144 ** 1145 ** Parameters: 1146 ** err -- the errno code to classify. 1147 ** 1148 ** Returns: 1149 ** TRUE if this is probably transient. 1150 ** FALSE otherwise. 1151 */ 1152 1153 bool 1154 transienterror(err) 1155 int err; 1156 { 1157 switch (err) 1158 { 1159 case EIO: /* I/O error */ 1160 case ENXIO: /* Device not configured */ 1161 case EAGAIN: /* Resource temporarily unavailable */ 1162 case ENOMEM: /* Cannot allocate memory */ 1163 case ENODEV: /* Operation not supported by device */ 1164 case ENFILE: /* Too many open files in system */ 1165 case EMFILE: /* Too many open files */ 1166 case ENOSPC: /* No space left on device */ 1167 #ifdef ETIMEDOUT 1168 case ETIMEDOUT: /* Connection timed out */ 1169 #endif 1170 #ifdef ESTALE 1171 case ESTALE: /* Stale NFS file handle */ 1172 #endif 1173 #ifdef ENETDOWN 1174 case ENETDOWN: /* Network is down */ 1175 #endif 1176 #ifdef ENETUNREACH 1177 case ENETUNREACH: /* Network is unreachable */ 1178 #endif 1179 #ifdef ENETRESET 1180 case ENETRESET: /* Network dropped connection on reset */ 1181 #endif 1182 #ifdef ECONNABORTED 1183 case ECONNABORTED: /* Software caused connection abort */ 1184 #endif 1185 #ifdef ECONNRESET 1186 case ECONNRESET: /* Connection reset by peer */ 1187 #endif 1188 #ifdef ENOBUFS 1189 case ENOBUFS: /* No buffer space available */ 1190 #endif 1191 #ifdef ESHUTDOWN 1192 case ESHUTDOWN: /* Can't send after socket shutdown */ 1193 #endif 1194 #ifdef ECONNREFUSED 1195 case ECONNREFUSED: /* Connection refused */ 1196 #endif 1197 #ifdef EHOSTDOWN 1198 case EHOSTDOWN: /* Host is down */ 1199 #endif 1200 #ifdef EHOSTUNREACH 1201 case EHOSTUNREACH: /* No route to host */ 1202 #endif 1203 #ifdef EDQUOT 1204 case EDQUOT: /* Disc quota exceeded */ 1205 #endif 1206 #ifdef EPROCLIM 1207 case EPROCLIM: /* Too many processes */ 1208 #endif 1209 #ifdef EUSERS 1210 case EUSERS: /* Too many users */ 1211 #endif 1212 #ifdef EDEADLK 1213 case EDEADLK: /* Resource deadlock avoided */ 1214 #endif 1215 #ifdef EISCONN 1216 case EISCONN: /* Socket already connected */ 1217 #endif 1218 #ifdef EINPROGRESS 1219 case EINPROGRESS: /* Operation now in progress */ 1220 #endif 1221 #ifdef EALREADY 1222 case EALREADY: /* Operation already in progress */ 1223 #endif 1224 #ifdef EADDRINUSE 1225 case EADDRINUSE: /* Address already in use */ 1226 #endif 1227 #ifdef EADDRNOTAVAIL 1228 case EADDRNOTAVAIL: /* Can't assign requested address */ 1229 #endif 1230 #ifdef ENOSR 1231 case ENOSR: /* Out of streams resources */ 1232 #endif 1233 return TRUE; 1234 } 1235 1236 /* nope, must be permanent */ 1237 return FALSE; 1238 } 1239