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