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