1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)conf.c 8.18 (Berkeley) 08/14/93"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include "pathnames.h" 15 # include <sys/ioctl.h> 16 # include <sys/param.h> 17 # include <pwd.h> 18 19 /* 20 ** CONF.C -- Sendmail Configuration Tables. 21 ** 22 ** Defines the configuration of this installation. 23 ** 24 ** Configuration Variables: 25 ** HdrInfo -- a table describing well-known header fields. 26 ** Each entry has the field name and some flags, 27 ** which are described in sendmail.h. 28 ** 29 ** Notes: 30 ** I have tried to put almost all the reasonable 31 ** configuration information into the configuration 32 ** file read at runtime. My intent is that anything 33 ** here is a function of the version of UNIX you 34 ** are running, or is really static -- for example 35 ** the headers are a superset of widely used 36 ** protocols. If you find yourself playing with 37 ** this file too much, you may be making a mistake! 38 */ 39 40 41 42 43 /* 44 ** Header info table 45 ** Final (null) entry contains the flags used for any other field. 46 ** 47 ** Not all of these are actually handled specially by sendmail 48 ** at this time. They are included as placeholders, to let 49 ** you know that "someday" I intend to have sendmail do 50 ** something with them. 51 */ 52 53 struct hdrinfo HdrInfo[] = 54 { 55 /* originator fields, most to least significant */ 56 "resent-sender", H_FROM|H_RESENT, 57 "resent-from", H_FROM|H_RESENT, 58 "resent-reply-to", H_FROM|H_RESENT, 59 "sender", H_FROM, 60 "from", H_FROM, 61 "reply-to", H_FROM, 62 "full-name", H_ACHECK, 63 "return-receipt-to", H_FROM /* |H_RECEIPTTO */, 64 "errors-to", H_FROM|H_ERRORSTO, 65 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 75 /* message identification and control */ 76 "message-id", 0, 77 "resent-message-id", H_RESENT, 78 "message", H_EOH, 79 "text", H_EOH, 80 81 /* date fields */ 82 "date", 0, 83 "resent-date", H_RESENT, 84 85 /* trace fields */ 86 "received", H_TRACE|H_FORCE, 87 "x400-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_FORCE|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 = (RealUid != 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 SevenBit = FALSE; /* option 7 */ 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 ** HOST_MAP_INIT -- initialize host class structures 203 */ 204 205 bool 206 host_map_init(map, args) 207 MAP *map; 208 char *args; 209 { 210 register char *p = args; 211 212 for (;;) 213 { 214 while (isascii(*p) && isspace(*p)) 215 p++; 216 if (*p != '-') 217 break; 218 switch (*++p) 219 { 220 case 'a': 221 map->map_app = ++p; 222 break; 223 } 224 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 225 p++; 226 if (*p != '\0') 227 *p++ = '\0'; 228 } 229 if (map->map_app != NULL) 230 map->map_app = newstr(map->map_app); 231 return TRUE; 232 } 233 /* 234 ** SETUPMAILERS -- initialize default mailers 235 */ 236 237 setupmailers() 238 { 239 char buf[100]; 240 241 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 242 makemailer(buf); 243 244 strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE"); 245 makemailer(buf); 246 247 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 248 makemailer(buf); 249 } 250 /* 251 ** SETUPMAPS -- set up map classes 252 */ 253 254 #define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \ 255 { \ 256 extern bool parse __P((MAP *, char *)); \ 257 extern bool open __P((MAP *, int)); \ 258 extern void close __P((MAP *)); \ 259 extern char *lookup __P((MAP *, char *, char **, int *)); \ 260 extern void store __P((MAP *, char *, char *)); \ 261 s = stab(name, ST_MAPCLASS, ST_ENTER); \ 262 s->s_mapclass.map_cname = name; \ 263 s->s_mapclass.map_ext = ext; \ 264 s->s_mapclass.map_cflags = flags; \ 265 s->s_mapclass.map_parse = parse; \ 266 s->s_mapclass.map_open = open; \ 267 s->s_mapclass.map_close = close; \ 268 s->s_mapclass.map_lookup = lookup; \ 269 s->s_mapclass.map_store = store; \ 270 } 271 272 setupmaps() 273 { 274 register STAB *s; 275 276 #ifdef NEWDB 277 MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 278 map_parseargs, hash_map_open, db_map_close, 279 db_map_lookup, db_map_store); 280 MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 281 map_parseargs, bt_map_open, db_map_close, 282 db_map_lookup, db_map_store); 283 #endif 284 285 #ifdef NDBM 286 MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE, 287 map_parseargs, ndbm_map_open, ndbm_map_close, 288 ndbm_map_lookup, ndbm_map_store); 289 #endif 290 291 #ifdef NIS 292 MAPDEF("nis", NULL, MCF_ALIASOK, 293 map_parseargs, nis_map_open, nis_map_close, 294 nis_map_lookup, nis_map_store); 295 #endif 296 297 MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY, 298 map_parseargs, stab_map_open, stab_map_close, 299 stab_map_lookup, stab_map_store); 300 301 MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE, 302 map_parseargs, impl_map_open, impl_map_close, 303 impl_map_lookup, impl_map_store); 304 305 /* host DNS lookup */ 306 MAPDEF("host", NULL, 0, 307 host_map_init, null_map_open, null_map_close, 308 host_map_lookup, null_map_store); 309 310 /* dequote map */ 311 MAPDEF("dequote", NULL, 0, 312 dequote_init, null_map_open, null_map_close, 313 dequote_map, null_map_store); 314 315 #if 0 316 # ifdef USERDB 317 /* user database */ 318 MAPDEF("udb", ".db", 0, 319 udb_map_parse, null_map_open, null_map_close, 320 udb_map_lookup, null_map_store); 321 # endif 322 #endif 323 } 324 325 #undef MAPDEF 326 /* 327 ** USERNAME -- return the user id of the logged in user. 328 ** 329 ** Parameters: 330 ** none. 331 ** 332 ** Returns: 333 ** The login name of the logged in user. 334 ** 335 ** Side Effects: 336 ** none. 337 ** 338 ** Notes: 339 ** The return value is statically allocated. 340 */ 341 342 char * 343 username() 344 { 345 static char *myname = NULL; 346 extern char *getlogin(); 347 register struct passwd *pw; 348 349 /* cache the result */ 350 if (myname == NULL) 351 { 352 myname = getlogin(); 353 if (myname == NULL || myname[0] == '\0') 354 { 355 pw = getpwuid(RealUid); 356 if (pw != NULL) 357 myname = newstr(pw->pw_name); 358 } 359 else 360 { 361 uid_t uid = RealUid; 362 363 myname = newstr(myname); 364 if ((pw = getpwnam(myname)) == NULL || 365 (uid != 0 && uid != pw->pw_uid)) 366 { 367 pw = getpwuid(uid); 368 if (pw != NULL) 369 myname = newstr(pw->pw_name); 370 } 371 } 372 if (myname == NULL || myname[0] == '\0') 373 { 374 syserr("554 Who are you?"); 375 myname = "postmaster"; 376 } 377 } 378 379 return (myname); 380 } 381 /* 382 ** TTYPATH -- Get the path of the user's tty 383 ** 384 ** Returns the pathname of the user's tty. Returns NULL if 385 ** the user is not logged in or if s/he has write permission 386 ** denied. 387 ** 388 ** Parameters: 389 ** none 390 ** 391 ** Returns: 392 ** pathname of the user's tty. 393 ** NULL if not logged in or write permission denied. 394 ** 395 ** Side Effects: 396 ** none. 397 ** 398 ** WARNING: 399 ** Return value is in a local buffer. 400 ** 401 ** Called By: 402 ** savemail 403 */ 404 405 char * 406 ttypath() 407 { 408 struct stat stbuf; 409 register char *pathn; 410 extern char *ttyname(); 411 extern char *getlogin(); 412 413 /* compute the pathname of the controlling tty */ 414 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 415 (pathn = ttyname(0)) == NULL) 416 { 417 errno = 0; 418 return (NULL); 419 } 420 421 /* see if we have write permission */ 422 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 423 { 424 errno = 0; 425 return (NULL); 426 } 427 428 /* see if the user is logged in */ 429 if (getlogin() == NULL) 430 return (NULL); 431 432 /* looks good */ 433 return (pathn); 434 } 435 /* 436 ** CHECKCOMPAT -- check for From and To person compatible. 437 ** 438 ** This routine can be supplied on a per-installation basis 439 ** to determine whether a person is allowed to send a message. 440 ** This allows restriction of certain types of internet 441 ** forwarding or registration of users. 442 ** 443 ** If the hosts are found to be incompatible, an error 444 ** message should be given using "usrerr" and 0 should 445 ** be returned. 446 ** 447 ** 'NoReturn' can be set to suppress the return-to-sender 448 ** function; this should be done on huge messages. 449 ** 450 ** Parameters: 451 ** to -- the person being sent to. 452 ** 453 ** Returns: 454 ** an exit status 455 ** 456 ** Side Effects: 457 ** none (unless you include the usrerr stuff) 458 */ 459 460 checkcompat(to, e) 461 register ADDRESS *to; 462 register ENVELOPE *e; 463 { 464 # ifdef lint 465 if (to == NULL) 466 to++; 467 # endif /* lint */ 468 # ifdef EXAMPLE_CODE 469 /* this code is intended as an example only */ 470 register STAB *s; 471 472 s = stab("arpa", ST_MAILER, ST_FIND); 473 if (s != NULL && e->e_from.q_mailer != LocalMailer && 474 to->q_mailer == s->s_mailer) 475 { 476 usrerr("553 No ARPA mail through this machine: see your system administration"); 477 /* NoReturn = TRUE; to supress return copy */ 478 return (EX_UNAVAILABLE); 479 } 480 # endif /* EXAMPLE_CODE */ 481 return (EX_OK); 482 } 483 /* 484 ** SETSIGNAL -- set a signal handler 485 ** 486 ** This is essentially old BSD "signal(3)". 487 */ 488 489 setsig_t 490 setsignal(sig, handler) 491 int sig; 492 setsig_t handler; 493 { 494 #if defined(SYS5SIGNALS) || defined(BSD4_3) 495 return signal(sig, handler); 496 #else 497 struct sigaction n, o; 498 499 bzero(&n, sizeof n); 500 n.sa_handler = handler; 501 if (sigaction(sig, &n, &o) < 0) 502 return SIG_ERR; 503 return o.sa_handler; 504 #endif 505 } 506 /* 507 ** HOLDSIGS -- arrange to hold all signals 508 ** 509 ** Parameters: 510 ** none. 511 ** 512 ** Returns: 513 ** none. 514 ** 515 ** Side Effects: 516 ** Arranges that signals are held. 517 */ 518 519 holdsigs() 520 { 521 } 522 /* 523 ** RLSESIGS -- arrange to release all signals 524 ** 525 ** This undoes the effect of holdsigs. 526 ** 527 ** Parameters: 528 ** none. 529 ** 530 ** Returns: 531 ** none. 532 ** 533 ** Side Effects: 534 ** Arranges that signals are released. 535 */ 536 537 rlsesigs() 538 { 539 } 540 /* 541 ** GETLA -- get the current load average 542 ** 543 ** This code stolen from la.c. 544 ** 545 ** Parameters: 546 ** none. 547 ** 548 ** Returns: 549 ** The current load average as an integer. 550 ** 551 ** Side Effects: 552 ** none. 553 */ 554 555 /* try to guess what style of load average we have */ 556 #define LA_ZERO 1 /* always return load average as zero */ 557 #define LA_INT 2 /* read kmem for avenrun; interpret as int */ 558 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 559 #define LA_SUBR 4 /* call getloadavg */ 560 561 /* do guesses based on general OS type */ 562 #ifndef LA_TYPE 563 # define LA_TYPE LA_ZERO 564 #endif 565 566 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) 567 568 #include <nlist.h> 569 570 #ifndef LA_AVENRUN 571 # ifdef SYSTEM5 572 # define LA_AVENRUN "avenrun" 573 # else 574 # define LA_AVENRUN "_avenrun" 575 # endif 576 #endif 577 578 /* _PATH_UNIX should be defined in <paths.h> */ 579 #ifndef _PATH_UNIX 580 # if defined(SYSTEM5) 581 # define _PATH_UNIX "/unix" 582 # else 583 # define _PATH_UNIX "/vmunix" 584 # endif 585 #endif 586 587 struct nlist Nl[] = 588 { 589 { LA_AVENRUN }, 590 #define X_AVENRUN 0 591 { 0 }, 592 }; 593 594 #ifndef FSHIFT 595 # if defined(unixpc) 596 # define FSHIFT 5 597 # endif 598 599 # if defined(__alpha) 600 # define FSHIFT 10 601 # endif 602 603 # if (LA_TYPE == LA_INT) 604 # define FSHIFT 8 605 # endif 606 #endif 607 608 #if (LA_TYPE == LA_INT) && !defined(FSCALE) 609 # define FSCALE (1 << FSHIFT) 610 #endif 611 612 getla() 613 { 614 static int kmem = -1; 615 #if LA_TYPE == LA_INT 616 long avenrun[3]; 617 #else 618 double avenrun[3]; 619 #endif 620 extern off_t lseek(); 621 extern int errno; 622 623 if (kmem < 0) 624 { 625 kmem = open("/dev/kmem", 0, 0); 626 if (kmem < 0) 627 { 628 if (tTd(3, 1)) 629 printf("getla: open(/dev/kmem): %s\n", 630 errstring(errno)); 631 return (-1); 632 } 633 (void) fcntl(kmem, F_SETFD, 1); 634 if (nlist(_PATH_UNIX, Nl) < 0) 635 { 636 if (tTd(3, 1)) 637 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 638 errstring(errno)); 639 return (-1); 640 } 641 if (Nl[X_AVENRUN].n_value == 0) 642 { 643 if (tTd(3, 1)) 644 printf("getla: nlist(%s, %s) ==> 0\n", 645 _PATH_UNIX, LA_AVENRUN); 646 return (-1); 647 } 648 } 649 if (tTd(3, 20)) 650 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 651 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 652 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 653 { 654 /* thank you Ian */ 655 if (tTd(3, 1)) 656 printf("getla: lseek or read: %s\n", errstring(errno)); 657 return (-1); 658 } 659 #if LA_TYPE == LA_INT 660 if (tTd(3, 5)) 661 { 662 printf("getla: avenrun = %d", avenrun[0]); 663 if (tTd(3, 15)) 664 printf(", %d, %d", avenrun[1], avenrun[2]); 665 printf("\n"); 666 } 667 if (tTd(3, 1)) 668 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 669 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 670 #else 671 if (tTd(3, 5)) 672 { 673 printf("getla: avenrun = %g", avenrun[0]); 674 if (tTd(3, 15)) 675 printf(", %g, %g", avenrun[1], avenrun[2]); 676 printf("\n"); 677 } 678 if (tTd(3, 1)) 679 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 680 return ((int) (avenrun[0] + 0.5)); 681 #endif 682 } 683 684 #else 685 #if LA_TYPE == LA_SUBR 686 687 getla() 688 { 689 double avenrun[3]; 690 691 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 692 { 693 if (tTd(3, 1)) 694 perror("getla: getloadavg failed:"); 695 return (-1); 696 } 697 if (tTd(3, 1)) 698 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 699 return ((int) (avenrun[0] + 0.5)); 700 } 701 702 #else 703 704 getla() 705 { 706 if (tTd(3, 1)) 707 printf("getla: ZERO\n"); 708 return (0); 709 } 710 711 #endif 712 #endif 713 /* 714 ** SHOULDQUEUE -- should this message be queued or sent? 715 ** 716 ** Compares the message cost to the load average to decide. 717 ** 718 ** Parameters: 719 ** pri -- the priority of the message in question. 720 ** ctime -- the message creation time. 721 ** 722 ** Returns: 723 ** TRUE -- if this message should be queued up for the 724 ** time being. 725 ** FALSE -- if the load is low enough to send this message. 726 ** 727 ** Side Effects: 728 ** none. 729 */ 730 731 bool 732 shouldqueue(pri, ctime) 733 long pri; 734 time_t ctime; 735 { 736 if (CurrentLA < QueueLA) 737 return (FALSE); 738 if (CurrentLA >= RefuseLA) 739 return (TRUE); 740 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 741 } 742 /* 743 ** REFUSECONNECTIONS -- decide if connections should be refused 744 ** 745 ** Parameters: 746 ** none. 747 ** 748 ** Returns: 749 ** TRUE if incoming SMTP connections should be refused 750 ** (for now). 751 ** FALSE if we should accept new work. 752 ** 753 ** Side Effects: 754 ** none. 755 */ 756 757 bool 758 refuseconnections() 759 { 760 #ifdef XLA 761 if (!xla_smtp_ok()) 762 return TRUE; 763 #endif 764 765 /* this is probably too simplistic */ 766 return (CurrentLA >= RefuseLA); 767 } 768 /* 769 ** SETPROCTITLE -- set process title for ps 770 ** 771 ** Parameters: 772 ** fmt -- a printf style format string. 773 ** a, b, c -- possible parameters to fmt. 774 ** 775 ** Returns: 776 ** none. 777 ** 778 ** Side Effects: 779 ** Clobbers argv of our main procedure so ps(1) will 780 ** display the title. 781 */ 782 783 #ifdef SETPROCTITLE 784 # ifdef __hpux 785 # include <sys/pstat.h> 786 # endif 787 # ifdef BSD4_4 788 # include <machine/vmparam.h> 789 # include <sys/exec.h> 790 # ifdef __bsdi__ 791 # undef PS_STRINGS /* BSDI 1.0 doesn't do PS_STRINGS as we expect */ 792 # endif 793 # ifdef PS_STRINGS 794 # define SETPROC_STATIC static 795 # endif 796 # endif 797 # ifndef SETPROC_STATIC 798 # define SETPROC_STATIC 799 # endif 800 #endif 801 802 /*VARARGS1*/ 803 #ifdef __STDC__ 804 setproctitle(char *fmt, ...) 805 #else 806 setproctitle(fmt, va_alist) 807 char *fmt; 808 va_dcl 809 #endif 810 { 811 # ifdef SETPROCTITLE 812 register char *p; 813 register int i; 814 SETPROC_STATIC char buf[MAXLINE]; 815 VA_LOCAL_DECL 816 # ifdef __hpux 817 union pstun pst; 818 # endif 819 extern char **Argv; 820 extern char *LastArgv; 821 822 p = buf; 823 824 /* print sendmail: heading for grep */ 825 (void) strcpy(p, "sendmail: "); 826 p += strlen(p); 827 828 /* print the argument string */ 829 VA_START(fmt); 830 (void) vsprintf(p, fmt, ap); 831 VA_END; 832 833 i = strlen(buf); 834 835 # ifdef __hpux 836 pst.pst_command = buf; 837 pstat(PSTAT_SETCMD, pst, i, 0, 0); 838 # else 839 # ifdef PS_STRINGS 840 PS_STRINGS->ps_nargvstr = 1; 841 PS_STRINGS->ps_argvstr = buf; 842 # else 843 if (i > LastArgv - Argv[0] - 2) 844 { 845 i = LastArgv - Argv[0] - 2; 846 buf[i] = '\0'; 847 } 848 (void) strcpy(Argv[0], buf); 849 p = &Argv[0][i]; 850 while (p < LastArgv) 851 *p++ = ' '; 852 # endif 853 # endif 854 # endif /* SETPROCTITLE */ 855 } 856 /* 857 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 858 ** 859 ** Parameters: 860 ** none. 861 ** 862 ** Returns: 863 ** none. 864 ** 865 ** Side Effects: 866 ** Picks up extant zombies. 867 */ 868 869 # include <sys/wait.h> 870 871 void 872 reapchild() 873 { 874 # ifdef HASWAITPID 875 auto int status; 876 int count; 877 int pid; 878 879 count = 0; 880 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 881 { 882 if (count++ > 1000) 883 { 884 syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", 885 pid, status); 886 break; 887 } 888 } 889 # else 890 # ifdef WNOHANG 891 union wait status; 892 893 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) 894 continue; 895 # else /* WNOHANG */ 896 auto int status; 897 898 while (wait(&status) > 0) 899 continue; 900 # endif /* WNOHANG */ 901 # endif 902 # ifdef SYS5SIGNALS 903 (void) setsignal(SIGCHLD, reapchild); 904 # endif 905 } 906 /* 907 ** UNSETENV -- remove a variable from the environment 908 ** 909 ** Not needed on newer systems. 910 ** 911 ** Parameters: 912 ** name -- the string name of the environment variable to be 913 ** deleted from the current environment. 914 ** 915 ** Returns: 916 ** none. 917 ** 918 ** Globals: 919 ** environ -- a pointer to the current environment. 920 ** 921 ** Side Effects: 922 ** Modifies environ. 923 */ 924 925 #ifndef HASUNSETENV 926 927 void 928 unsetenv(name) 929 char *name; 930 { 931 extern char **environ; 932 register char **pp; 933 int len = strlen(name); 934 935 for (pp = environ; *pp != NULL; pp++) 936 { 937 if (strncmp(name, *pp, len) == 0 && 938 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 939 break; 940 } 941 942 for (; *pp != NULL; pp++) 943 *pp = pp[1]; 944 } 945 946 #endif 947 /* 948 ** GETDTABLESIZE -- return number of file descriptors 949 ** 950 ** Only on non-BSD systems 951 ** 952 ** Parameters: 953 ** none 954 ** 955 ** Returns: 956 ** size of file descriptor table 957 ** 958 ** Side Effects: 959 ** none 960 */ 961 962 #ifdef SOLARIS 963 # include <sys/resource.h> 964 #endif 965 966 int 967 getdtsize() 968 { 969 #ifdef RLIMIT_NOFILE 970 struct rlimit rl; 971 972 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 973 return rl.rlim_cur; 974 #endif 975 976 # ifdef HASGETDTABLESIZE 977 return getdtablesize(); 978 # else 979 # ifdef _SC_OPEN_MAX 980 return sysconf(_SC_OPEN_MAX); 981 # else 982 return NOFILE; 983 # endif 984 # endif 985 } 986 /* 987 ** UNAME -- get the UUCP name of this system. 988 */ 989 990 #ifndef HASUNAME 991 992 int 993 uname(name) 994 struct utsname *name; 995 { 996 FILE *file; 997 char *n; 998 999 name->nodename[0] = '\0'; 1000 1001 /* try /etc/whoami -- one line with the node name */ 1002 if ((file = fopen("/etc/whoami", "r")) != NULL) 1003 { 1004 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 1005 (void) fclose(file); 1006 n = strchr(name->nodename, '\n'); 1007 if (n != NULL) 1008 *n = '\0'; 1009 if (name->nodename[0] != '\0') 1010 return (0); 1011 } 1012 1013 /* try /usr/include/whoami.h -- has a #define somewhere */ 1014 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 1015 { 1016 char buf[MAXLINE]; 1017 1018 while (fgets(buf, MAXLINE, file) != NULL) 1019 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 1020 NODE_LENGTH, name->nodename) > 0) 1021 break; 1022 (void) fclose(file); 1023 if (name->nodename[0] != '\0') 1024 return (0); 1025 } 1026 1027 #ifdef TRUST_POPEN 1028 /* 1029 ** Popen is known to have security holes. 1030 */ 1031 1032 /* try uuname -l to return local name */ 1033 if ((file = popen("uuname -l", "r")) != NULL) 1034 { 1035 (void) fgets(name, NODE_LENGTH + 1, file); 1036 (void) pclose(file); 1037 n = strchr(name, '\n'); 1038 if (n != NULL) 1039 *n = '\0'; 1040 if (name->nodename[0] != '\0') 1041 return (0); 1042 } 1043 #endif 1044 1045 return (-1); 1046 } 1047 #endif /* HASUNAME */ 1048 /* 1049 ** INITGROUPS -- initialize groups 1050 ** 1051 ** Stub implementation for System V style systems 1052 */ 1053 1054 #ifndef HASINITGROUPS 1055 1056 initgroups(name, basegid) 1057 char *name; 1058 int basegid; 1059 { 1060 return 0; 1061 } 1062 1063 #endif 1064 /* 1065 ** SETSID -- set session id (for non-POSIX systems) 1066 */ 1067 1068 #ifndef HASSETSID 1069 1070 pid_t 1071 setsid __P ((void)) 1072 { 1073 #ifdef TIOCNOTTY 1074 int fd; 1075 1076 fd = open("/dev/tty", 2); 1077 if (fd >= 0) 1078 { 1079 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); 1080 (void) close(fd); 1081 } 1082 #endif /* TIOCNOTTY */ 1083 # ifdef SYSTEM5 1084 return setpgrp(); 1085 # else 1086 return setpgid(0, getpid()); 1087 # endif 1088 } 1089 1090 #endif 1091 /* 1092 ** GETOPT -- for old systems or systems with bogus implementations 1093 */ 1094 1095 #ifdef NEEDGETOPT 1096 1097 /* 1098 * Copyright (c) 1985 Regents of the University of California. 1099 * All rights reserved. The Berkeley software License Agreement 1100 * specifies the terms and conditions for redistribution. 1101 */ 1102 1103 1104 /* 1105 ** this version hacked to add `atend' flag to allow state machine 1106 ** to reset if invoked by the program to scan args for a 2nd time 1107 */ 1108 1109 #if defined(LIBC_SCCS) && !defined(lint) 1110 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 1111 #endif /* LIBC_SCCS and not lint */ 1112 1113 #include <stdio.h> 1114 1115 /* 1116 * get option letter from argument vector 1117 */ 1118 int opterr = 1, /* if error message should be printed */ 1119 optind = 1, /* index into parent argv vector */ 1120 optopt; /* character checked for validity */ 1121 char *optarg; /* argument associated with option */ 1122 1123 #define BADCH (int)'?' 1124 #define EMSG "" 1125 #define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \ 1126 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} 1127 1128 getopt(nargc,nargv,ostr) 1129 int nargc; 1130 char **nargv, 1131 *ostr; 1132 { 1133 static char *place = EMSG; /* option letter processing */ 1134 static char atend = 0; 1135 register char *oli; /* option letter list index */ 1136 1137 if (atend) { 1138 atend = 0; 1139 place = EMSG; 1140 } 1141 if(!*place) { /* update scanning pointer */ 1142 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 1143 atend++; 1144 return(EOF); 1145 } 1146 if (*place == '-') { /* found "--" */ 1147 ++optind; 1148 atend++; 1149 return(EOF); 1150 } 1151 } /* option letter okay? */ 1152 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { 1153 if (!*place) ++optind; 1154 tell(": illegal option -- "); 1155 } 1156 if (*++oli != ':') { /* don't need argument */ 1157 optarg = NULL; 1158 if (!*place) ++optind; 1159 } 1160 else { /* need an argument */ 1161 if (*place) optarg = place; /* no white space */ 1162 else if (nargc <= ++optind) { /* no arg */ 1163 place = EMSG; 1164 tell(": option requires an argument -- "); 1165 } 1166 else optarg = nargv[optind]; /* white space */ 1167 place = EMSG; 1168 ++optind; 1169 } 1170 return(optopt); /* dump back option letter */ 1171 } 1172 1173 #endif 1174 /* 1175 ** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version 1176 */ 1177 1178 #ifdef NEEDVPRINTF 1179 1180 #define MAXARG 16 1181 1182 vfprintf(fp, fmt, ap) 1183 FILE * fp; 1184 char * fmt; 1185 char ** ap; 1186 { 1187 char * bp[MAXARG]; 1188 int i = 0; 1189 1190 while (*ap && i < MAXARG) 1191 bp[i++] = *ap++; 1192 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3], 1193 bp[4], bp[5], bp[6], bp[7], 1194 bp[8], bp[9], bp[10], bp[11], 1195 bp[12], bp[13], bp[14], bp[15]); 1196 } 1197 1198 vsprintf(s, fmt, ap) 1199 char * s; 1200 char * fmt; 1201 char ** ap; 1202 { 1203 char * bp[MAXARG]; 1204 int i = 0; 1205 1206 while (*ap && i < MAXARG) 1207 bp[i++] = *ap++; 1208 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3], 1209 bp[4], bp[5], bp[6], bp[7], 1210 bp[8], bp[9], bp[10], bp[11], 1211 bp[12], bp[13], bp[14], bp[15]); 1212 } 1213 1214 #endif 1215 /* 1216 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1217 ** 1218 ** Only implemented if you have statfs. 1219 ** 1220 ** Parameters: 1221 ** msize -- the size to check against. If zero, we don't yet 1222 ** know how big the message will be, so just check for 1223 ** a "reasonable" amount. 1224 ** 1225 ** Returns: 1226 ** TRUE if there is enough space. 1227 ** FALSE otherwise. 1228 */ 1229 1230 #ifndef HASSTATFS 1231 # if defined(BSD4_4) || defined(__osf__) 1232 # define HASSTATFS 1233 # endif 1234 #endif 1235 1236 #ifdef HASSTATFS 1237 # undef HASUSTAT 1238 #endif 1239 1240 #if defined(HASUSTAT) 1241 # include <ustat.h> 1242 #endif 1243 1244 #ifdef HASSTATFS 1245 # if defined(sgi) || defined(apollo) || defined(_SCO_unix_) 1246 # include <sys/statfs.h> 1247 # else 1248 # if (defined(sun) && !defined(BSD)) || defined(__hpux) || defined(_CONVEX_SOURCE) 1249 # include <sys/vfs.h> 1250 # else 1251 # include <sys/mount.h> 1252 # endif 1253 # endif 1254 #endif 1255 1256 bool 1257 enoughspace(msize) 1258 long msize; 1259 { 1260 #if defined(HASSTATFS) || defined(HASUSTAT) 1261 # if defined(HASUSTAT) 1262 struct ustat fs; 1263 struct stat statbuf; 1264 # define FSBLOCKSIZE DEV_BSIZE 1265 # define f_bavail f_tfree 1266 # else 1267 # if defined(ultrix) 1268 struct fs_data fs; 1269 # define f_bavail fd_bfreen 1270 # define FSBLOCKSIZE fs.fd_bsize 1271 # else 1272 struct statfs fs; 1273 # define FSBLOCKSIZE fs.f_bsize 1274 # if defined(_SCO_unix_) 1275 # define f_bavail f_bfree 1276 # endif 1277 # endif 1278 # endif 1279 extern int errno; 1280 1281 if (MinBlocksFree <= 0 && msize <= 0) 1282 { 1283 if (tTd(4, 80)) 1284 printf("enoughspace: no threshold\n"); 1285 return TRUE; 1286 } 1287 1288 if (msize < 0) 1289 msize = 0; 1290 1291 # if defined(HASUSTAT) 1292 if (stat(QueueDir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1293 # else 1294 # if defined(sgi) || defined(apollo) 1295 if (statfs(QueueDir, &fs, sizeof fs, 0) == 0) 1296 # else 1297 # if defined(ultrix) 1298 if (statfs(QueueDir, &fs) > 0) 1299 # else 1300 if (statfs(QueueDir, &fs) == 0) 1301 # endif 1302 # endif 1303 # endif 1304 { 1305 if (tTd(4, 80)) 1306 printf("enoughspace: bavail=%ld, need=%ld\n", 1307 fs.f_bavail, msize); 1308 1309 /* convert msize to block count */ 1310 msize = msize / FSBLOCKSIZE + 1; 1311 if (MinBlocksFree >= 0) 1312 msize += MinBlocksFree; 1313 1314 if (fs.f_bavail < msize) 1315 { 1316 #ifdef LOG 1317 if (LogLevel > 0) 1318 syslog(LOG_ALERT, 1319 "%s: low on space (have %ld, %s needs %ld in %s)", 1320 CurEnv->e_id, fs.f_bavail, 1321 CurHostName, msize, QueueDir); 1322 #endif 1323 return FALSE; 1324 } 1325 } 1326 else if (tTd(4, 80)) 1327 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1328 MinBlocksFree, msize, errstring(errno)); 1329 #endif 1330 return TRUE; 1331 } 1332 /* 1333 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1334 ** 1335 ** This looks at an errno value and tells if this is likely to 1336 ** go away if retried later. 1337 ** 1338 ** Parameters: 1339 ** err -- the errno code to classify. 1340 ** 1341 ** Returns: 1342 ** TRUE if this is probably transient. 1343 ** FALSE otherwise. 1344 */ 1345 1346 bool 1347 transienterror(err) 1348 int err; 1349 { 1350 switch (err) 1351 { 1352 case EIO: /* I/O error */ 1353 case ENXIO: /* Device not configured */ 1354 case EAGAIN: /* Resource temporarily unavailable */ 1355 case ENOMEM: /* Cannot allocate memory */ 1356 case ENODEV: /* Operation not supported by device */ 1357 case ENFILE: /* Too many open files in system */ 1358 case EMFILE: /* Too many open files */ 1359 case ENOSPC: /* No space left on device */ 1360 #ifdef ETIMEDOUT 1361 case ETIMEDOUT: /* Connection timed out */ 1362 #endif 1363 #ifdef ESTALE 1364 case ESTALE: /* Stale NFS file handle */ 1365 #endif 1366 #ifdef ENETDOWN 1367 case ENETDOWN: /* Network is down */ 1368 #endif 1369 #ifdef ENETUNREACH 1370 case ENETUNREACH: /* Network is unreachable */ 1371 #endif 1372 #ifdef ENETRESET 1373 case ENETRESET: /* Network dropped connection on reset */ 1374 #endif 1375 #ifdef ECONNABORTED 1376 case ECONNABORTED: /* Software caused connection abort */ 1377 #endif 1378 #ifdef ECONNRESET 1379 case ECONNRESET: /* Connection reset by peer */ 1380 #endif 1381 #ifdef ENOBUFS 1382 case ENOBUFS: /* No buffer space available */ 1383 #endif 1384 #ifdef ESHUTDOWN 1385 case ESHUTDOWN: /* Can't send after socket shutdown */ 1386 #endif 1387 #ifdef ECONNREFUSED 1388 case ECONNREFUSED: /* Connection refused */ 1389 #endif 1390 #ifdef EHOSTDOWN 1391 case EHOSTDOWN: /* Host is down */ 1392 #endif 1393 #ifdef EHOSTUNREACH 1394 case EHOSTUNREACH: /* No route to host */ 1395 #endif 1396 #ifdef EDQUOT 1397 case EDQUOT: /* Disc quota exceeded */ 1398 #endif 1399 #ifdef EPROCLIM 1400 case EPROCLIM: /* Too many processes */ 1401 #endif 1402 #ifdef EUSERS 1403 case EUSERS: /* Too many users */ 1404 #endif 1405 #ifdef EDEADLK 1406 case EDEADLK: /* Resource deadlock avoided */ 1407 #endif 1408 #ifdef EISCONN 1409 case EISCONN: /* Socket already connected */ 1410 #endif 1411 #ifdef EINPROGRESS 1412 case EINPROGRESS: /* Operation now in progress */ 1413 #endif 1414 #ifdef EALREADY 1415 case EALREADY: /* Operation already in progress */ 1416 #endif 1417 #ifdef EADDRINUSE 1418 case EADDRINUSE: /* Address already in use */ 1419 #endif 1420 #ifdef EADDRNOTAVAIL 1421 case EADDRNOTAVAIL: /* Can't assign requested address */ 1422 #endif 1423 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 1424 case ENOSR: /* Out of streams resources */ 1425 #endif 1426 return TRUE; 1427 } 1428 1429 /* nope, must be permanent */ 1430 return FALSE; 1431 } 1432 /* 1433 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 1434 ** 1435 ** Parameters: 1436 ** fd -- the file descriptor of the file. 1437 ** filename -- the file name (for error messages). 1438 ** type -- type of the lock. Bits can be: 1439 ** LOCK_EX -- exclusive lock. 1440 ** LOCK_NB -- non-blocking. 1441 ** 1442 ** Returns: 1443 ** TRUE if the lock was acquired. 1444 ** FALSE otherwise. 1445 */ 1446 1447 bool 1448 lockfile(fd, filename, type) 1449 int fd; 1450 char *filename; 1451 int type; 1452 { 1453 # ifndef HASFLOCK 1454 int action; 1455 struct flock lfd; 1456 1457 bzero(&lfd, sizeof lfd); 1458 if (bitset(LOCK_UN, type)) 1459 lfd.l_type = F_UNLCK; 1460 else if (bitset(LOCK_EX, type)) 1461 lfd.l_type = F_WRLCK; 1462 else 1463 lfd.l_type = F_RDLCK; 1464 1465 if (bitset(LOCK_NB, type)) 1466 action = F_SETLK; 1467 else 1468 action = F_SETLKW; 1469 1470 if (fcntl(fd, action, &lfd) >= 0) 1471 return TRUE; 1472 1473 /* 1474 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 1475 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 1476 ** as type "tmp" (that is, served from swap space), the 1477 ** previous fcntl will fail with "Invalid argument" errors. 1478 ** Since this is fairly common during testing, we will assume 1479 ** that this indicates that the lock is successfully grabbed. 1480 */ 1481 1482 if (errno == EINVAL) 1483 return TRUE; 1484 1485 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 1486 syserr("cannot lockf(%s, %o)", filename, type); 1487 # else 1488 if (flock(fd, type) >= 0) 1489 return TRUE; 1490 1491 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 1492 syserr("cannot flock(%s, %o)", filename, type); 1493 # endif 1494 return FALSE; 1495 } 1496