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