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