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.36 (Berkeley) 03/17/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 588 #ifndef LA_AVENRUN 589 #define LA_AVENRUN "_avenrun" 590 #endif 591 592 /* _PATH_UNIX should be defined in <paths.h> */ 593 #ifndef _PATH_UNIX 594 # if defined(hpux) 595 # define _PATH_UNIX "/hp-ux" 596 # endif 597 # if defined(mips) && !defined(ultrix) 598 /* powerful RISC/os */ 599 # define _PATH_UNIX "/unix" 600 # endif 601 # if defined(SYSTEM5) 602 # ifndef _PATH_UNIX 603 # define _PATH_UNIX "/unix" 604 # endif 605 # endif 606 # ifndef _PATH_UNIX 607 # define _PATH_UNIX "/vmunix" 608 # endif 609 #endif 610 611 struct nlist Nl[] = 612 { 613 { LA_AVENRUN }, 614 #define X_AVENRUN 0 615 { 0 }, 616 }; 617 618 #if defined(unixpc) 619 # define FSHIFT 5 620 #endif 621 622 #if defined(__alpha) 623 # define FSHIFT 10 624 #endif 625 626 #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 627 # define FSHIFT 8 628 #endif 629 #if (LA_TYPE == LA_INT) && !defined(FSCALE) 630 # define FSCALE (1 << FSHIFT) 631 #endif 632 633 getla() 634 { 635 static int kmem = -1; 636 #if LA_TYPE == LA_INT 637 long avenrun[3]; 638 #else 639 double avenrun[3]; 640 #endif 641 extern off_t lseek(); 642 extern char *errstring(); 643 extern int errno; 644 645 if (kmem < 0) 646 { 647 kmem = open("/dev/kmem", 0, 0); 648 if (kmem < 0) 649 { 650 if (tTd(3, 1)) 651 printf("getla: open(/dev/kmem): %s\n", 652 errstring(errno)); 653 return (-1); 654 } 655 (void) fcntl(kmem, F_SETFD, 1); 656 if (nlist(_PATH_UNIX, Nl) < 0) 657 { 658 if (tTd(3, 1)) 659 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 660 errstring(errno)); 661 return (-1); 662 } 663 } 664 if (tTd(3, 20)) 665 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 666 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 667 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 668 { 669 /* thank you Ian */ 670 if (tTd(3, 1)) 671 printf("getla: lseek or read: %s\n", errstring(errno)); 672 return (-1); 673 } 674 #if LA_TYPE == LA_INT 675 if (tTd(3, 5)) 676 { 677 printf("getla: avenrun = %d", avenrun[0]); 678 if (tTd(3, 15)) 679 printf(", %d, %d", avenrun[1], avenrun[2]); 680 printf("\n"); 681 } 682 if (tTd(3, 1)) 683 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 684 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 685 #else 686 if (tTd(3, 5)) 687 { 688 printf("getla: avenrun = %g", avenrun[0]); 689 if (tTd(3, 15)) 690 printf(", %g, %g", avenrun[1], avenrun[2]); 691 printf("\n"); 692 } 693 if (tTd(3, 1)) 694 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 695 return ((int) (avenrun[0] + 0.5)); 696 #endif 697 } 698 699 #else 700 #if LA_TYPE == LA_SUBR 701 702 getla() 703 { 704 double avenrun[3]; 705 706 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 707 { 708 if (tTd(3, 1)) 709 perror("getla: getloadavg failed:"); 710 return (-1); 711 } 712 if (tTd(3, 1)) 713 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 714 return ((int) (avenrun[0] + 0.5)); 715 } 716 717 #else 718 719 getla() 720 { 721 if (tTd(3, 1)) 722 printf("getla: ZERO\n"); 723 return (0); 724 } 725 726 #endif 727 #endif 728 /* 729 ** SHOULDQUEUE -- should this message be queued or sent? 730 ** 731 ** Compares the message cost to the load average to decide. 732 ** 733 ** Parameters: 734 ** pri -- the priority of the message in question. 735 ** ctime -- the message creation time. 736 ** 737 ** Returns: 738 ** TRUE -- if this message should be queued up for the 739 ** time being. 740 ** FALSE -- if the load is low enough to send this message. 741 ** 742 ** Side Effects: 743 ** none. 744 */ 745 746 bool 747 shouldqueue(pri, ctime) 748 long pri; 749 time_t ctime; 750 { 751 if (CurrentLA < QueueLA) 752 return (FALSE); 753 if (CurrentLA >= RefuseLA) 754 return (TRUE); 755 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 756 } 757 /* 758 ** REFUSECONNECTIONS -- decide if connections should be refused 759 ** 760 ** Parameters: 761 ** none. 762 ** 763 ** Returns: 764 ** TRUE if incoming SMTP connections should be refused 765 ** (for now). 766 ** FALSE if we should accept new work. 767 ** 768 ** Side Effects: 769 ** none. 770 */ 771 772 bool 773 refuseconnections() 774 { 775 /* this is probably too simplistic */ 776 return (CurrentLA >= RefuseLA); 777 } 778 /* 779 ** SETPROCTITLE -- set process title for ps 780 ** 781 ** Parameters: 782 ** fmt -- a printf style format string. 783 ** a, b, c -- possible parameters to fmt. 784 ** 785 ** Returns: 786 ** none. 787 ** 788 ** Side Effects: 789 ** Clobbers argv of our main procedure so ps(1) will 790 ** display the title. 791 */ 792 793 #ifdef SETPROCTITLE 794 # ifdef __hpux 795 # include <sys/pstat.h> 796 # endif 797 #endif 798 799 /*VARARGS1*/ 800 #ifdef __STDC__ 801 setproctitle(char *fmt, ...) 802 #else 803 setproctitle(fmt, va_alist) 804 char *fmt; 805 va_dcl 806 #endif 807 { 808 # ifdef SETPROCTITLE 809 register char *p; 810 register int i; 811 char buf[MAXLINE]; 812 VA_LOCAL_DECL 813 # ifdef __hpux 814 union pstun pst; 815 # endif 816 extern char **Argv; 817 extern char *LastArgv; 818 819 p = buf; 820 821 /* print sendmail: heading for grep */ 822 (void) strcpy(p, "sendmail: "); 823 p += strlen(p); 824 825 /* print the argument string */ 826 VA_START(fmt); 827 (void) vsprintf(p, fmt, ap); 828 VA_END; 829 830 i = strlen(buf); 831 832 # ifdef __hpux 833 pst.pst_command = buf; 834 pstat(PSTAT_SETCMD, pst, i, 0, 0); 835 # else 836 837 if (i > LastArgv - Argv[0] - 2) 838 { 839 i = LastArgv - Argv[0] - 2; 840 buf[i] = '\0'; 841 } 842 (void) strcpy(Argv[0], buf); 843 p = &Argv[0][i]; 844 while (p < LastArgv) 845 *p++ = ' '; 846 # endif 847 # endif /* SETPROCTITLE */ 848 } 849 /* 850 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 851 ** 852 ** Parameters: 853 ** none. 854 ** 855 ** Returns: 856 ** none. 857 ** 858 ** Side Effects: 859 ** Picks up extant zombies. 860 */ 861 862 # include <sys/wait.h> 863 864 void 865 reapchild() 866 { 867 # ifdef WNOHANG 868 union wait status; 869 870 while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 871 continue; 872 # else /* WNOHANG */ 873 auto int status; 874 875 while (wait((int *)&status) > 0) 876 continue; 877 # endif /* WNOHANG */ 878 # ifdef SYSTEM5 879 (void) signal(SIGCHLD, reapchild); 880 # endif 881 } 882 /* 883 ** UNSETENV -- remove a variable from the environment 884 ** 885 ** Not needed on newer systems. 886 ** 887 ** Parameters: 888 ** name -- the string name of the environment variable to be 889 ** deleted from the current environment. 890 ** 891 ** Returns: 892 ** none. 893 ** 894 ** Globals: 895 ** environ -- a pointer to the current environment. 896 ** 897 ** Side Effects: 898 ** Modifies environ. 899 */ 900 901 #ifdef UNSETENV 902 903 void 904 unsetenv(name) 905 char *name; 906 { 907 extern char **environ; 908 register char **pp; 909 int len = strlen(name); 910 911 for (pp = environ; *pp != NULL; pp++) 912 { 913 if (strncmp(name, *pp, len) == 0 && 914 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 915 break; 916 } 917 918 for (; *pp != NULL; pp++) 919 *pp = pp[1]; 920 } 921 922 #endif /* UNSETENV */ 923 /* 924 ** GETDTABLESIZE -- return number of file descriptors 925 ** 926 ** Only on non-BSD systems 927 ** 928 ** Parameters: 929 ** none 930 ** 931 ** Returns: 932 ** size of file descriptor table 933 ** 934 ** Side Effects: 935 ** none 936 */ 937 938 #ifdef SYSTEM5 939 940 int 941 getdtablesize() 942 { 943 # ifdef _SC_OPEN_MAX 944 return sysconf(_SC_OPEN_MAX); 945 # else 946 return NOFILE; 947 # endif 948 } 949 950 #endif 951 /* 952 ** UNAME -- get the UUCP name of this system. 953 */ 954 955 #ifndef HASUNAME 956 957 int 958 uname(name) 959 struct utsname *name; 960 { 961 FILE *file; 962 char *n; 963 964 name->nodename[0] = '\0'; 965 966 /* try /etc/whoami -- one line with the node name */ 967 if ((file = fopen("/etc/whoami", "r")) != NULL) 968 { 969 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 970 (void) fclose(file); 971 n = strchr(name->nodename, '\n'); 972 if (n != NULL) 973 *n = '\0'; 974 if (name->nodename[0] != '\0') 975 return (0); 976 } 977 978 /* try /usr/include/whoami.h -- has a #define somewhere */ 979 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 980 { 981 char buf[MAXLINE]; 982 983 while (fgets(buf, MAXLINE, file) != NULL) 984 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 985 NODE_LENGTH, name->nodename) > 0) 986 break; 987 (void) fclose(file); 988 if (name->nodename[0] != '\0') 989 return (0); 990 } 991 992 #ifdef TRUST_POPEN 993 /* 994 ** Popen is known to have security holes. 995 */ 996 997 /* try uuname -l to return local name */ 998 if ((file = popen("uuname -l", "r")) != NULL) 999 { 1000 (void) fgets(name, NODE_LENGTH + 1, file); 1001 (void) pclose(file); 1002 n = strchr(name, '\n'); 1003 if (n != NULL) 1004 *n = '\0'; 1005 if (name->nodename[0] != '\0') 1006 return (0); 1007 } 1008 #endif 1009 1010 return (-1); 1011 } 1012 #endif /* HASUNAME */ 1013 /* 1014 ** INITGROUPS -- initialize groups 1015 ** 1016 ** Stub implementation for System V style systems 1017 */ 1018 1019 #ifndef HASINITGROUPS 1020 # if !defined(SYSTEM5) || defined(hpux) 1021 # define HASINITGROUPS 1022 # endif 1023 #endif 1024 1025 #ifndef HASINITGROUPS 1026 1027 initgroups(name, basegid) 1028 char *name; 1029 int basegid; 1030 { 1031 return 0; 1032 } 1033 1034 #endif 1035 /* 1036 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1037 ** 1038 ** Only implemented if you have statfs. 1039 ** 1040 ** Parameters: 1041 ** msize -- the size to check against. If zero, we don't yet 1042 ** know how big the message will be, so just check for 1043 ** a "reasonable" amount. 1044 ** 1045 ** Returns: 1046 ** TRUE if there is enough space. 1047 ** FALSE otherwise. 1048 */ 1049 1050 #ifndef HASSTATFS 1051 # if defined(BSD4_4) || defined(__osf__) 1052 # define HASSTATFS 1053 # endif 1054 #endif 1055 1056 #ifdef HASSTATFS 1057 # undef HASUSTAT 1058 #endif 1059 1060 #if defined(HASUSTAT) 1061 # include <sys/stat.h> 1062 # include <ustat.h> 1063 #endif 1064 1065 #ifdef HASSTATFS 1066 # if defined(sgi) || defined(apollo) 1067 # include <sys/statfs.h> 1068 # else 1069 # if defined(sun) || defined(hpux) 1070 # include <sys/vfs.h> 1071 # else 1072 # include <sys/mount.h> 1073 # endif 1074 # endif 1075 #endif 1076 1077 bool 1078 enoughspace(msize) 1079 long msize; 1080 { 1081 #if defined(HASSTATFS) || defined(HASUSTAT) 1082 # if defined(HASUSTAT) 1083 struct ustat fs; 1084 struct stat statbuf; 1085 # define FSBLOCKSIZE DEV_BSIZE 1086 # define f_bavail f_tfree 1087 # else 1088 # if defined(ultrix) 1089 struct fs_data fs; 1090 # define f_bavail fd_bfreen 1091 # define FSBLOCKSIZE fs.fd_bsize 1092 # else 1093 struct statfs fs; 1094 # define FSBLOCKSIZE fs.f_bsize 1095 # endif 1096 # endif 1097 long blocksneeded; 1098 extern int errno; 1099 extern char *errstring(); 1100 1101 if (MinBlocksFree <= 0 && msize <= 0) 1102 { 1103 if (tTd(4, 80)) 1104 printf("enoughspace: no threshold\n"); 1105 return TRUE; 1106 } 1107 1108 # if defined(HASUSTAT) 1109 if (stat(QueueDir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1110 # else 1111 # if defined(sgi) || defined(apollo) 1112 if (statfs(QueueDir, &fs, sizeof fs, 0) == 0) 1113 # else 1114 # if defined(ultrix) 1115 if (statfs(QueueDir, &fs) > 0) 1116 # else 1117 if (statfs(QueueDir, &fs) == 0) 1118 # endif 1119 # endif 1120 # endif 1121 { 1122 if (tTd(4, 80)) 1123 printf("enoughspace: bavail=%ld, need=%ld\n", 1124 fs.f_bavail, msize); 1125 1126 /* convert msize to block count */ 1127 msize = msize / FSBLOCKSIZE + 1; 1128 if (MinBlocksFree >= 0) 1129 msize += MinBlocksFree; 1130 1131 if (fs.f_bavail < msize) 1132 { 1133 #ifdef LOG 1134 if (LogLevel > 0) 1135 syslog(LOG_ALERT, "%s: low on space (have %ld, need %ld)", 1136 QueueDir, fs.f_bavail, msize); 1137 #endif 1138 return FALSE; 1139 } 1140 } 1141 else if (tTd(4, 80)) 1142 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1143 MinBlocksFree, msize, errstring(errno)); 1144 #endif 1145 return TRUE; 1146 } 1147 /* 1148 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1149 ** 1150 ** This looks at an errno value and tells if this is likely to 1151 ** go away if retried later. 1152 ** 1153 ** Parameters: 1154 ** err -- the errno code to classify. 1155 ** 1156 ** Returns: 1157 ** TRUE if this is probably transient. 1158 ** FALSE otherwise. 1159 */ 1160 1161 bool 1162 transienterror(err) 1163 int err; 1164 { 1165 switch (err) 1166 { 1167 case EIO: /* I/O error */ 1168 case ENXIO: /* Device not configured */ 1169 case EAGAIN: /* Resource temporarily unavailable */ 1170 case ENOMEM: /* Cannot allocate memory */ 1171 case ENODEV: /* Operation not supported by device */ 1172 case ENFILE: /* Too many open files in system */ 1173 case EMFILE: /* Too many open files */ 1174 case ENOSPC: /* No space left on device */ 1175 #ifdef ETIMEDOUT 1176 case ETIMEDOUT: /* Connection timed out */ 1177 #endif 1178 #ifdef ESTALE 1179 case ESTALE: /* Stale NFS file handle */ 1180 #endif 1181 #ifdef ENETDOWN 1182 case ENETDOWN: /* Network is down */ 1183 #endif 1184 #ifdef ENETUNREACH 1185 case ENETUNREACH: /* Network is unreachable */ 1186 #endif 1187 #ifdef ENETRESET 1188 case ENETRESET: /* Network dropped connection on reset */ 1189 #endif 1190 #ifdef ECONNABORTED 1191 case ECONNABORTED: /* Software caused connection abort */ 1192 #endif 1193 #ifdef ECONNRESET 1194 case ECONNRESET: /* Connection reset by peer */ 1195 #endif 1196 #ifdef ENOBUFS 1197 case ENOBUFS: /* No buffer space available */ 1198 #endif 1199 #ifdef ESHUTDOWN 1200 case ESHUTDOWN: /* Can't send after socket shutdown */ 1201 #endif 1202 #ifdef ECONNREFUSED 1203 case ECONNREFUSED: /* Connection refused */ 1204 #endif 1205 #ifdef EHOSTDOWN 1206 case EHOSTDOWN: /* Host is down */ 1207 #endif 1208 #ifdef EHOSTUNREACH 1209 case EHOSTUNREACH: /* No route to host */ 1210 #endif 1211 #ifdef EDQUOT 1212 case EDQUOT: /* Disc quota exceeded */ 1213 #endif 1214 #ifdef EPROCLIM 1215 case EPROCLIM: /* Too many processes */ 1216 #endif 1217 #ifdef EUSERS 1218 case EUSERS: /* Too many users */ 1219 #endif 1220 #ifdef EDEADLK 1221 case EDEADLK: /* Resource deadlock avoided */ 1222 #endif 1223 #ifdef EISCONN 1224 case EISCONN: /* Socket already connected */ 1225 #endif 1226 #ifdef EINPROGRESS 1227 case EINPROGRESS: /* Operation now in progress */ 1228 #endif 1229 #ifdef EALREADY 1230 case EALREADY: /* Operation already in progress */ 1231 #endif 1232 #ifdef EADDRINUSE 1233 case EADDRINUSE: /* Address already in use */ 1234 #endif 1235 #ifdef EADDRNOTAVAIL 1236 case EADDRNOTAVAIL: /* Can't assign requested address */ 1237 #endif 1238 #ifdef ENOSR 1239 case ENOSR: /* Out of streams resources */ 1240 #endif 1241 return TRUE; 1242 } 1243 1244 /* nope, must be permanent */ 1245 return FALSE; 1246 } 1247 /* 1248 ** LOCKFILE -- lock a file using flock or (shudder) lockf 1249 ** 1250 ** Parameters: 1251 ** fd -- the file descriptor of the file. 1252 ** filename -- the file name (for error messages). 1253 ** type -- type of the lock. Bits can be: 1254 ** LOCK_EX -- exclusive lock. 1255 ** LOCK_NB -- non-blocking. 1256 ** 1257 ** Returns: 1258 ** TRUE if the lock was acquired. 1259 ** FALSE otherwise. 1260 */ 1261 1262 bool 1263 lockfile(fd, filename, type) 1264 int fd; 1265 char *filename; 1266 int type; 1267 { 1268 # ifdef LOCKF 1269 int action; 1270 struct flock lfd; 1271 1272 if (bitset(LOCK_EX, type) 1273 lfd.l_type = F_WRLCK; 1274 else 1275 lfd.l_type = F_RDLCK; 1276 1277 if (bitset(LOCK_NB, type)) 1278 action = F_SETLK; 1279 else 1280 action = F_SETLKW; 1281 1282 lfd.l_whence = lfd.l_start = lfd.l_len = 0; 1283 1284 if (fcntl(fd, action, &lfd) >= 0) 1285 return TRUE; 1286 1287 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 1288 syserr("cannot lockf(%s)", filename); 1289 # else 1290 if (flock(fd, type) >= 0) 1291 return TRUE; 1292 1293 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 1294 syserr("cannot flock(%s)", filename); 1295 # endif 1296 return FALSE; 1297 } 1298