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.12 (Berkeley) 07/26/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 #ifdef SYS5SIGNALS 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 PS_STRINGS 791 # define SETPROC_STATIC static 792 # endif 793 # endif 794 # ifndef SETPROC_STATIC 795 # define SETPROC_STATIC 796 # endif 797 #endif 798 799 /*VARARGS1*/ 800 #ifdef __STDC__ 801 setproctitle(char *fmt, ...) 802 #else 803 setproctitle(fmt, va_alist) 804 char *fmt; 805 va_dcl 806 #endif 807 { 808 # ifdef SETPROCTITLE 809 register char *p; 810 register int i; 811 SETPROC_STATIC char buf[MAXLINE]; 812 VA_LOCAL_DECL 813 # ifdef __hpux 814 union pstun pst; 815 # endif 816 extern char **Argv; 817 extern char *LastArgv; 818 819 p = buf; 820 821 /* print sendmail: heading for grep */ 822 (void) strcpy(p, "sendmail: "); 823 p += strlen(p); 824 825 /* print the argument string */ 826 VA_START(fmt); 827 (void) vsprintf(p, fmt, ap); 828 VA_END; 829 830 i = strlen(buf); 831 832 # ifdef __hpux 833 pst.pst_command = buf; 834 pstat(PSTAT_SETCMD, pst, i, 0, 0); 835 # else 836 # ifdef PS_STRINGS 837 PS_STRINGS->ps_nargvstr = 1; 838 PS_STRINGS->ps_argvstr = buf; 839 # else 840 if (i > LastArgv - Argv[0] - 2) 841 { 842 i = LastArgv - Argv[0] - 2; 843 buf[i] = '\0'; 844 } 845 (void) strcpy(Argv[0], buf); 846 p = &Argv[0][i]; 847 while (p < LastArgv) 848 *p++ = ' '; 849 # endif 850 # endif 851 # endif /* SETPROCTITLE */ 852 } 853 /* 854 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 855 ** 856 ** Parameters: 857 ** none. 858 ** 859 ** Returns: 860 ** none. 861 ** 862 ** Side Effects: 863 ** Picks up extant zombies. 864 */ 865 866 # include <sys/wait.h> 867 868 void 869 reapchild() 870 { 871 # ifdef HASWAITPID 872 auto int status; 873 int count; 874 int pid; 875 876 count = 0; 877 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 878 { 879 if (count++ > 1000) 880 { 881 syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", 882 pid, status); 883 break; 884 } 885 } 886 # else 887 # ifdef WNOHANG 888 union wait status; 889 890 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) 891 continue; 892 # else /* WNOHANG */ 893 auto int status; 894 895 while (wait(&status) > 0) 896 continue; 897 # endif /* WNOHANG */ 898 # endif 899 # ifdef SYS5SIGNALS 900 (void) setsignal(SIGCHLD, reapchild); 901 # endif 902 } 903 /* 904 ** SETENV -- set environment variable 905 ** 906 ** Putenv is more modern, but this is a simpler interface 907 ** 908 ** Parameters: 909 ** name -- the name of the envariable. 910 ** value -- the value of that envariable. 911 ** overwrite -- if set, overwrite existing value 912 ** (this is assumed to be set). 913 ** 914 ** Returns: 915 ** none. 916 ** 917 ** Side Effects: 918 ** The environment is updated. 919 */ 920 921 #ifndef HASSETENV 922 923 setenv(name, value, overwrite) 924 char *name; 925 char *value; 926 int overwrite; 927 { 928 register char *p; 929 930 p = xalloc(strlen(name) + strlen(value) + 2); 931 strcpy(p, name); 932 strcat(p, "="); 933 strcat(p, value); 934 putenv(p); 935 } 936 937 #endif 938 /* 939 ** UNSETENV -- remove a variable from the environment 940 ** 941 ** Not needed on newer systems. 942 ** 943 ** Parameters: 944 ** name -- the string name of the environment variable to be 945 ** deleted from the current environment. 946 ** 947 ** Returns: 948 ** none. 949 ** 950 ** Globals: 951 ** environ -- a pointer to the current environment. 952 ** 953 ** Side Effects: 954 ** Modifies environ. 955 */ 956 957 #ifndef HASUNSETENV 958 959 void 960 unsetenv(name) 961 char *name; 962 { 963 extern char **environ; 964 register char **pp; 965 int len = strlen(name); 966 967 for (pp = environ; *pp != NULL; pp++) 968 { 969 if (strncmp(name, *pp, len) == 0 && 970 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 971 break; 972 } 973 974 for (; *pp != NULL; pp++) 975 *pp = pp[1]; 976 } 977 978 #endif 979 /* 980 ** GETDTABLESIZE -- return number of file descriptors 981 ** 982 ** Only on non-BSD systems 983 ** 984 ** Parameters: 985 ** none 986 ** 987 ** Returns: 988 ** size of file descriptor table 989 ** 990 ** Side Effects: 991 ** none 992 */ 993 994 #ifdef SOLARIS 995 # include <sys/resource.h> 996 #endif 997 998 int 999 getdtsize() 1000 { 1001 #ifdef RLIMIT_NOFILE 1002 struct rlimit rl; 1003 1004 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 1005 return rl.rlim_cur; 1006 #endif 1007 1008 # ifdef HASGETDTABLESIZE 1009 return getdtablesize(); 1010 # else 1011 # ifdef _SC_OPEN_MAX 1012 return sysconf(_SC_OPEN_MAX); 1013 # else 1014 return NOFILE; 1015 # endif 1016 # endif 1017 } 1018 /* 1019 ** UNAME -- get the UUCP name of this system. 1020 */ 1021 1022 #ifndef HASUNAME 1023 1024 int 1025 uname(name) 1026 struct utsname *name; 1027 { 1028 FILE *file; 1029 char *n; 1030 1031 name->nodename[0] = '\0'; 1032 1033 /* try /etc/whoami -- one line with the node name */ 1034 if ((file = fopen("/etc/whoami", "r")) != NULL) 1035 { 1036 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 1037 (void) fclose(file); 1038 n = strchr(name->nodename, '\n'); 1039 if (n != NULL) 1040 *n = '\0'; 1041 if (name->nodename[0] != '\0') 1042 return (0); 1043 } 1044 1045 /* try /usr/include/whoami.h -- has a #define somewhere */ 1046 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 1047 { 1048 char buf[MAXLINE]; 1049 1050 while (fgets(buf, MAXLINE, file) != NULL) 1051 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 1052 NODE_LENGTH, name->nodename) > 0) 1053 break; 1054 (void) fclose(file); 1055 if (name->nodename[0] != '\0') 1056 return (0); 1057 } 1058 1059 #ifdef TRUST_POPEN 1060 /* 1061 ** Popen is known to have security holes. 1062 */ 1063 1064 /* try uuname -l to return local name */ 1065 if ((file = popen("uuname -l", "r")) != NULL) 1066 { 1067 (void) fgets(name, NODE_LENGTH + 1, file); 1068 (void) pclose(file); 1069 n = strchr(name, '\n'); 1070 if (n != NULL) 1071 *n = '\0'; 1072 if (name->nodename[0] != '\0') 1073 return (0); 1074 } 1075 #endif 1076 1077 return (-1); 1078 } 1079 #endif /* HASUNAME */ 1080 /* 1081 ** INITGROUPS -- initialize groups 1082 ** 1083 ** Stub implementation for System V style systems 1084 */ 1085 1086 #ifndef HASINITGROUPS 1087 1088 initgroups(name, basegid) 1089 char *name; 1090 int basegid; 1091 { 1092 return 0; 1093 } 1094 1095 #endif 1096 /* 1097 ** SETSID -- set session id (for non-POSIX systems) 1098 */ 1099 1100 #ifndef HASSETSID 1101 1102 pid_t 1103 setsid __P ((void)) 1104 { 1105 # ifdef SYSTEM5 1106 return setpgrp(); 1107 # else 1108 return 0; 1109 # endif 1110 } 1111 1112 #endif 1113 /* 1114 ** GETOPT -- for old systems or systems with bogus implementations 1115 */ 1116 1117 #ifdef NEEDGETOPT 1118 1119 /* 1120 * Copyright (c) 1985 Regents of the University of California. 1121 * All rights reserved. The Berkeley software License Agreement 1122 * specifies the terms and conditions for redistribution. 1123 */ 1124 1125 1126 /* 1127 ** this version hacked to add `atend' flag to allow state machine 1128 ** to reset if invoked by the program to scan args for a 2nd time 1129 */ 1130 1131 #if defined(LIBC_SCCS) && !defined(lint) 1132 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 1133 #endif LIBC_SCCS and not lint 1134 1135 #include <stdio.h> 1136 1137 /* 1138 * get option letter from argument vector 1139 */ 1140 int opterr = 1, /* if error message should be printed */ 1141 optind = 1, /* index into parent argv vector */ 1142 optopt; /* character checked for validity */ 1143 char *optarg; /* argument associated with option */ 1144 1145 #define BADCH (int)'?' 1146 #define EMSG "" 1147 #define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \ 1148 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} 1149 1150 getopt(nargc,nargv,ostr) 1151 int nargc; 1152 char **nargv, 1153 *ostr; 1154 { 1155 static char *place = EMSG; /* option letter processing */ 1156 static char atend = 0; 1157 register char *oli; /* option letter list index */ 1158 char *index(); 1159 1160 if (atend) { 1161 atend = 0; 1162 place = EMSG; 1163 } 1164 if(!*place) { /* update scanning pointer */ 1165 if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 1166 atend++; 1167 return(EOF); 1168 } 1169 if (*place == '-') { /* found "--" */ 1170 ++optind; 1171 atend++; 1172 return(EOF); 1173 } 1174 } /* option letter okay? */ 1175 if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) { 1176 if(!*place) ++optind; 1177 tell(": illegal option -- "); 1178 } 1179 if (*++oli != ':') { /* don't need argument */ 1180 optarg = NULL; 1181 if (!*place) ++optind; 1182 } 1183 else { /* need an argument */ 1184 if (*place) optarg = place; /* no white space */ 1185 else if (nargc <= ++optind) { /* no arg */ 1186 place = EMSG; 1187 tell(": option requires an argument -- "); 1188 } 1189 else optarg = nargv[optind]; /* white space */ 1190 place = EMSG; 1191 ++optind; 1192 } 1193 return(optopt); /* dump back option letter */ 1194 } 1195 1196 #endif 1197 /* 1198 ** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version 1199 */ 1200 1201 #ifdef NEEDVPRINTF 1202 1203 #define MAXARG 16 1204 1205 vfprintf(fp, fmt, ap) 1206 FILE * fp; 1207 char * fmt; 1208 char ** ap; 1209 { 1210 char * bp[MAXARG]; 1211 int i = 0; 1212 1213 while (*ap && i < MAXARG) 1214 bp[i++] = *ap++; 1215 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3], 1216 bp[4], bp[5], bp[6], bp[7], 1217 bp[8], bp[9], bp[10], bp[11], 1218 bp[12], bp[13], bp[14], bp[15]); 1219 } 1220 1221 vsprintf(s, fmt, ap) 1222 char * s; 1223 char * fmt; 1224 char ** ap; 1225 { 1226 char * bp[MAXARG]; 1227 int i = 0; 1228 1229 while (*ap && i < MAXARG) 1230 bp[i++] = *ap++; 1231 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3], 1232 bp[4], bp[5], bp[6], bp[7], 1233 bp[8], bp[9], bp[10], bp[11], 1234 bp[12], bp[13], bp[14], bp[15]); 1235 } 1236 1237 #endif 1238 /* 1239 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1240 ** 1241 ** Only implemented if you have statfs. 1242 ** 1243 ** Parameters: 1244 ** msize -- the size to check against. If zero, we don't yet 1245 ** know how big the message will be, so just check for 1246 ** a "reasonable" amount. 1247 ** 1248 ** Returns: 1249 ** TRUE if there is enough space. 1250 ** FALSE otherwise. 1251 */ 1252 1253 #ifndef HASSTATFS 1254 # if defined(BSD4_4) || defined(__osf__) 1255 # define HASSTATFS 1256 # endif 1257 #endif 1258 1259 #ifdef HASSTATFS 1260 # undef HASUSTAT 1261 #endif 1262 1263 #if defined(HASUSTAT) 1264 # include <ustat.h> 1265 #endif 1266 1267 #ifdef HASSTATFS 1268 # if defined(sgi) || defined(apollo) || defined(_SCO_unix_) 1269 # include <sys/statfs.h> 1270 # else 1271 # if (defined(sun) && !defined(BSD)) || defined(__hpux) || defined(_CONVEX_SOURCE) 1272 # include <sys/vfs.h> 1273 # else 1274 # include <sys/mount.h> 1275 # endif 1276 # endif 1277 #endif 1278 1279 bool 1280 enoughspace(msize) 1281 long msize; 1282 { 1283 #if defined(HASSTATFS) || defined(HASUSTAT) 1284 # if defined(HASUSTAT) 1285 struct ustat fs; 1286 struct stat statbuf; 1287 # define FSBLOCKSIZE DEV_BSIZE 1288 # define f_bavail f_tfree 1289 # else 1290 # if defined(ultrix) 1291 struct fs_data fs; 1292 # define f_bavail fd_bfreen 1293 # define FSBLOCKSIZE fs.fd_bsize 1294 # else 1295 struct statfs fs; 1296 # define FSBLOCKSIZE fs.f_bsize 1297 # if defined(_SCO_UNIX_) 1298 # define f_bavail f_bfree 1299 # endif 1300 # endif 1301 # endif 1302 extern int errno; 1303 1304 if (MinBlocksFree <= 0 && msize <= 0) 1305 { 1306 if (tTd(4, 80)) 1307 printf("enoughspace: no threshold\n"); 1308 return TRUE; 1309 } 1310 1311 # if defined(HASUSTAT) 1312 if (stat(QueueDir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1313 # else 1314 # if defined(sgi) || defined(apollo) 1315 if (statfs(QueueDir, &fs, sizeof fs, 0) == 0) 1316 # else 1317 # if defined(ultrix) 1318 if (statfs(QueueDir, &fs) > 0) 1319 # else 1320 if (statfs(QueueDir, &fs) == 0) 1321 # endif 1322 # endif 1323 # endif 1324 { 1325 if (tTd(4, 80)) 1326 printf("enoughspace: bavail=%ld, need=%ld\n", 1327 fs.f_bavail, msize); 1328 1329 /* convert msize to block count */ 1330 msize = msize / FSBLOCKSIZE + 1; 1331 if (MinBlocksFree >= 0) 1332 msize += MinBlocksFree; 1333 1334 if (fs.f_bavail < msize) 1335 { 1336 #ifdef LOG 1337 if (LogLevel > 0) 1338 syslog(LOG_ALERT, "%s: low on space (have %ld, need %ld)", 1339 QueueDir, fs.f_bavail, msize); 1340 #endif 1341 return FALSE; 1342 } 1343 } 1344 else if (tTd(4, 80)) 1345 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1346 MinBlocksFree, msize, errstring(errno)); 1347 #endif 1348 return TRUE; 1349 } 1350 /* 1351 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1352 ** 1353 ** This looks at an errno value and tells if this is likely to 1354 ** go away if retried later. 1355 ** 1356 ** Parameters: 1357 ** err -- the errno code to classify. 1358 ** 1359 ** Returns: 1360 ** TRUE if this is probably transient. 1361 ** FALSE otherwise. 1362 */ 1363 1364 bool 1365 transienterror(err) 1366 int err; 1367 { 1368 switch (err) 1369 { 1370 case EIO: /* I/O error */ 1371 case ENXIO: /* Device not configured */ 1372 case EAGAIN: /* Resource temporarily unavailable */ 1373 case ENOMEM: /* Cannot allocate memory */ 1374 case ENODEV: /* Operation not supported by device */ 1375 case ENFILE: /* Too many open files in system */ 1376 case EMFILE: /* Too many open files */ 1377 case ENOSPC: /* No space left on device */ 1378 #ifdef ETIMEDOUT 1379 case ETIMEDOUT: /* Connection timed out */ 1380 #endif 1381 #ifdef ESTALE 1382 case ESTALE: /* Stale NFS file handle */ 1383 #endif 1384 #ifdef ENETDOWN 1385 case ENETDOWN: /* Network is down */ 1386 #endif 1387 #ifdef ENETUNREACH 1388 case ENETUNREACH: /* Network is unreachable */ 1389 #endif 1390 #ifdef ENETRESET 1391 case ENETRESET: /* Network dropped connection on reset */ 1392 #endif 1393 #ifdef ECONNABORTED 1394 case ECONNABORTED: /* Software caused connection abort */ 1395 #endif 1396 #ifdef ECONNRESET 1397 case ECONNRESET: /* Connection reset by peer */ 1398 #endif 1399 #ifdef ENOBUFS 1400 case ENOBUFS: /* No buffer space available */ 1401 #endif 1402 #ifdef ESHUTDOWN 1403 case ESHUTDOWN: /* Can't send after socket shutdown */ 1404 #endif 1405 #ifdef ECONNREFUSED 1406 case ECONNREFUSED: /* Connection refused */ 1407 #endif 1408 #ifdef EHOSTDOWN 1409 case EHOSTDOWN: /* Host is down */ 1410 #endif 1411 #ifdef EHOSTUNREACH 1412 case EHOSTUNREACH: /* No route to host */ 1413 #endif 1414 #ifdef EDQUOT 1415 case EDQUOT: /* Disc quota exceeded */ 1416 #endif 1417 #ifdef EPROCLIM 1418 case EPROCLIM: /* Too many processes */ 1419 #endif 1420 #ifdef EUSERS 1421 case EUSERS: /* Too many users */ 1422 #endif 1423 #ifdef EDEADLK 1424 case EDEADLK: /* Resource deadlock avoided */ 1425 #endif 1426 #ifdef EISCONN 1427 case EISCONN: /* Socket already connected */ 1428 #endif 1429 #ifdef EINPROGRESS 1430 case EINPROGRESS: /* Operation now in progress */ 1431 #endif 1432 #ifdef EALREADY 1433 case EALREADY: /* Operation already in progress */ 1434 #endif 1435 #ifdef EADDRINUSE 1436 case EADDRINUSE: /* Address already in use */ 1437 #endif 1438 #ifdef EADDRNOTAVAIL 1439 case EADDRNOTAVAIL: /* Can't assign requested address */ 1440 #endif 1441 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 1442 case ENOSR: /* Out of streams resources */ 1443 #endif 1444 return TRUE; 1445 } 1446 1447 /* nope, must be permanent */ 1448 return FALSE; 1449 } 1450 /* 1451 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 1452 ** 1453 ** Parameters: 1454 ** fd -- the file descriptor of the file. 1455 ** filename -- the file name (for error messages). 1456 ** type -- type of the lock. Bits can be: 1457 ** LOCK_EX -- exclusive lock. 1458 ** LOCK_NB -- non-blocking. 1459 ** 1460 ** Returns: 1461 ** TRUE if the lock was acquired. 1462 ** FALSE otherwise. 1463 */ 1464 1465 bool 1466 lockfile(fd, filename, type) 1467 int fd; 1468 char *filename; 1469 int type; 1470 { 1471 # ifndef HASFLOCK 1472 int action; 1473 struct flock lfd; 1474 1475 bzero(&lfd, sizeof lfd); 1476 if (bitset(LOCK_UN, type)) 1477 lfd.l_type = F_UNLCK; 1478 else if (bitset(LOCK_EX, type)) 1479 lfd.l_type = F_WRLCK; 1480 else 1481 lfd.l_type = F_RDLCK; 1482 1483 if (bitset(LOCK_NB, type)) 1484 action = F_SETLK; 1485 else 1486 action = F_SETLKW; 1487 1488 if (fcntl(fd, action, &lfd) >= 0) 1489 return TRUE; 1490 1491 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 1492 syserr("cannot lockf(%s, %o)", filename, type); 1493 # else 1494 if (flock(fd, type) >= 0) 1495 return TRUE; 1496 1497 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 1498 syserr("cannot flock(%s, %o)", filename, type); 1499 # endif 1500 return FALSE; 1501 } 1502