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