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.18 (Berkeley) 02/20/93"; 11 #endif /* not lint */ 12 13 # include <sys/ioctl.h> 14 # include <sys/param.h> 15 # include <pwd.h> 16 # include "sendmail.h" 17 # include "pathnames.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 /* destination fields */ 66 "to", H_RCPT, 67 "resent-to", H_RCPT|H_RESENT, 68 "cc", H_RCPT, 69 "resent-cc", H_RCPT|H_RESENT, 70 "bcc", H_RCPT|H_ACHECK, 71 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 72 "apparently-to", H_RCPT, 73 /* message identification and control */ 74 "message-id", 0, 75 "resent-message-id", H_RESENT, 76 "message", H_EOH, 77 "text", H_EOH, 78 /* date fields */ 79 "date", 0, 80 "resent-date", H_RESENT, 81 /* trace fields */ 82 "received", H_TRACE|H_FORCE, 83 "via", H_TRACE|H_FORCE, 84 "mail-from", H_TRACE|H_FORCE, 85 86 NULL, 0, 87 }; 88 89 90 /* 91 ** ARPANET error message numbers. 92 */ 93 94 char Arpa_Info[] = "050"; /* arbitrary info */ 95 char Arpa_TSyserr[] = "451"; /* some (transient) system error */ 96 char Arpa_PSyserr[] = "554"; /* some (permanent) system error */ 97 char Arpa_Usrerr[] = "501"; /* some (fatal) user error */ 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 "needexpnnelo", PRIV_NEEDEXPNHELO, 120 "needvrfyhelo", PRIV_NEEDVRFYHELO, 121 "noexpn", PRIV_NOEXPN, 122 "novrfy", PRIV_NOVRFY, 123 "goaway", PRIV_GOAWAY, 124 NULL, PRIV_PUBLIC, 125 }; 126 127 128 129 /* 130 ** Miscellaneous stuff. 131 */ 132 133 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 134 /* 135 ** SETDEFAULTS -- set default values 136 ** 137 ** Because of the way freezing is done, these must be initialized 138 ** using direct code. 139 ** 140 ** Parameters: 141 ** none. 142 ** 143 ** Returns: 144 ** none. 145 ** 146 ** Side Effects: 147 ** Initializes a bunch of global variables to their 148 ** default values. 149 */ 150 151 setdefaults() 152 { 153 SpaceSub = ' '; /* option B */ 154 QueueLA = 8; /* option x */ 155 RefuseLA = 12; /* option X */ 156 WkRecipFact = 30000L; /* option y */ 157 WkClassFact = 1800L; /* option z */ 158 WkTimeFact = 90000L; /* option Z */ 159 QueueFactor = WkRecipFact * 20; /* option q */ 160 FileMode = (getuid() != geteuid()) ? 0644 : 0600; 161 /* option F */ 162 DefUid = 1; /* option u */ 163 DefGid = 1; /* option g */ 164 CheckpointInterval = 10; /* option C */ 165 MaxHopCount = 25; /* option h */ 166 SendMode = SM_FORK; /* option d */ 167 ErrorMode = EM_PRINT; /* option e */ 168 EightBit = FALSE; /* option 8 */ 169 MaxMciCache = 1; /* option k */ 170 MciCacheTimeout = 300; /* option K */ 171 LogLevel = 9; /* option L */ 172 ReadTimeout = 2 * 60 * 60; /* option r */ 173 TimeOut = 3 * 24 * 60 * 60; /* option T */ 174 setdefuser(); 175 setupmaps(); 176 setupmailers(); 177 } 178 179 180 /* 181 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 182 */ 183 184 setdefuser() 185 { 186 struct passwd *defpwent; 187 static char defuserbuf[40]; 188 189 DefUser = defuserbuf; 190 if ((defpwent = getpwuid(DefUid)) != NULL) 191 strcpy(defuserbuf, defpwent->pw_name); 192 else 193 strcpy(defuserbuf, "nobody"); 194 } 195 /* 196 ** SETUPMAPS -- set up map classes 197 ** 198 ** Since these are compiled in, they cannot be in the config file. 199 ** 200 */ 201 202 setupmaps() 203 { 204 register STAB *s; 205 extern bool host_map_init(); 206 extern char *maphostname(); 207 208 /* set up host name lookup map */ 209 s = stab("host", ST_MAPCLASS, ST_ENTER); 210 s->s_mapclass.map_init = host_map_init; 211 s->s_mapclass.map_lookup = maphostname; 212 213 /* 214 ** Set up other map classes. 215 */ 216 217 # ifdef DBM_MAP 218 /* dbm file access */ 219 { 220 extern bool dbm_map_init(); 221 extern char *dbm_map_lookup(); 222 223 s = stab("dbm", ST_MAPCLASS, ST_ENTER); 224 s->s_mapclass.map_init = dbm_map_init; 225 s->s_mapclass.map_lookup = dbm_map_lookup; 226 } 227 # endif 228 229 # ifdef BTREE_MAP 230 /* new database file access -- btree files */ 231 { 232 extern bool bt_map_init(); 233 extern char *db_map_lookup(); 234 235 s = stab("btree", ST_MAPCLASS, ST_ENTER); 236 s->s_mapclass.map_init = bt_map_init; 237 s->s_mapclass.map_lookup = db_map_lookup; 238 } 239 # endif 240 241 # ifdef HASH_MAP 242 /* new database file access -- hash files */ 243 { 244 extern bool hash_map_init(); 245 extern char *db_map_lookup(); 246 247 s = stab("hash", ST_MAPCLASS, ST_ENTER); 248 s->s_mapclass.map_init = hash_map_init; 249 s->s_mapclass.map_lookup = db_map_lookup; 250 } 251 # endif 252 253 # ifdef NIS_MAP 254 /* NIS map access */ 255 { 256 extern bool nis_map_init(); 257 extern char *nis_map_lookup(); 258 259 s = stab("nis", ST_MAPCLASS, ST_ENTER); 260 s->s_mapclass.map_init = nis_map_init; 261 s->s_mapclass.map_lookup = nis_map_lookup; 262 } 263 # endif 264 265 # ifdef USERDB_MAP 266 /* user database */ 267 { 268 extern bool udb_map_init(); 269 extern char *udb_map_lookup(); 270 271 s = stab("udb", ST_MAPCLASS, ST_ENTER); 272 s->s_mapclass.map_init = udb_map_init; 273 s->s_mapclass.map_lookup = udb_map_lookup; 274 } 275 # endif 276 } 277 /* 278 ** HOST_MAP_INIT -- initialize host class structures 279 */ 280 281 bool 282 host_map_init(map, mapname, args) 283 MAP *map; 284 char *mapname; 285 char *args; 286 { 287 register char *p = args; 288 289 for (;;) 290 { 291 while (isascii(*p) && isspace(*p)) 292 p++; 293 if (*p != '-') 294 break; 295 switch (*++p) 296 { 297 case 'a': 298 map->map_app = ++p; 299 break; 300 } 301 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 302 p++; 303 if (*p != '\0') 304 *p++ = '\0'; 305 } 306 if (map->map_app != NULL) 307 map->map_app = newstr(map->map_app); 308 return TRUE; 309 } 310 /* 311 ** SETUPMAILERS -- initialize default mailers 312 */ 313 314 setupmailers() 315 { 316 char buf[100]; 317 318 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 319 makemailer(buf); 320 321 strcpy(buf, "*file*, P=/dev/null, F=lsDEu, A=FILE"); 322 makemailer(buf); 323 324 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 325 makemailer(buf); 326 } 327 /* 328 ** GETRUID -- get real user id (V7) 329 */ 330 331 getruid() 332 { 333 if (OpMode == MD_DAEMON) 334 return (RealUid); 335 else 336 return (getuid()); 337 } 338 339 340 /* 341 ** GETRGID -- get real group id (V7). 342 */ 343 344 getrgid() 345 { 346 if (OpMode == MD_DAEMON) 347 return (RealGid); 348 else 349 return (getgid()); 350 } 351 /* 352 ** USERNAME -- return the user id of the logged in user. 353 ** 354 ** Parameters: 355 ** none. 356 ** 357 ** Returns: 358 ** The login name of the logged in user. 359 ** 360 ** Side Effects: 361 ** none. 362 ** 363 ** Notes: 364 ** The return value is statically allocated. 365 */ 366 367 char * 368 username() 369 { 370 static char *myname = NULL; 371 extern char *getlogin(); 372 register struct passwd *pw; 373 374 /* cache the result */ 375 if (myname == NULL) 376 { 377 myname = getlogin(); 378 if (myname == NULL || myname[0] == '\0') 379 { 380 381 pw = getpwuid(getruid()); 382 if (pw != NULL) 383 myname = newstr(pw->pw_name); 384 } 385 else 386 { 387 388 myname = newstr(myname); 389 if ((pw = getpwnam(myname)) == NULL || 390 getuid() != pw->pw_uid) 391 { 392 pw = getpwuid(getuid()); 393 if (pw != NULL) 394 myname = newstr(pw->pw_name); 395 } 396 } 397 if (myname == NULL || myname[0] == '\0') 398 { 399 syserr("Who are you?"); 400 myname = "postmaster"; 401 } 402 } 403 404 return (myname); 405 } 406 /* 407 ** TTYPATH -- Get the path of the user's tty 408 ** 409 ** Returns the pathname of the user's tty. Returns NULL if 410 ** the user is not logged in or if s/he has write permission 411 ** denied. 412 ** 413 ** Parameters: 414 ** none 415 ** 416 ** Returns: 417 ** pathname of the user's tty. 418 ** NULL if not logged in or write permission denied. 419 ** 420 ** Side Effects: 421 ** none. 422 ** 423 ** WARNING: 424 ** Return value is in a local buffer. 425 ** 426 ** Called By: 427 ** savemail 428 */ 429 430 # include <sys/stat.h> 431 432 char * 433 ttypath() 434 { 435 struct stat stbuf; 436 register char *pathn; 437 extern char *ttyname(); 438 extern char *getlogin(); 439 440 /* compute the pathname of the controlling tty */ 441 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 442 (pathn = ttyname(0)) == NULL) 443 { 444 errno = 0; 445 return (NULL); 446 } 447 448 /* see if we have write permission */ 449 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 450 { 451 errno = 0; 452 return (NULL); 453 } 454 455 /* see if the user is logged in */ 456 if (getlogin() == NULL) 457 return (NULL); 458 459 /* looks good */ 460 return (pathn); 461 } 462 /* 463 ** CHECKCOMPAT -- check for From and To person compatible. 464 ** 465 ** This routine can be supplied on a per-installation basis 466 ** to determine whether a person is allowed to send a message. 467 ** This allows restriction of certain types of internet 468 ** forwarding or registration of users. 469 ** 470 ** If the hosts are found to be incompatible, an error 471 ** message should be given using "usrerr" and 0 should 472 ** be returned. 473 ** 474 ** 'NoReturn' can be set to suppress the return-to-sender 475 ** function; this should be done on huge messages. 476 ** 477 ** Parameters: 478 ** to -- the person being sent to. 479 ** 480 ** Returns: 481 ** an exit status 482 ** 483 ** Side Effects: 484 ** none (unless you include the usrerr stuff) 485 */ 486 487 checkcompat(to, e) 488 register ADDRESS *to; 489 register ENVELOPE *e; 490 { 491 # ifdef lint 492 if (to == NULL) 493 to++; 494 # endif lint 495 # ifdef EXAMPLE_CODE 496 /* this code is intended as an example only */ 497 register STAB *s; 498 499 s = stab("arpa", ST_MAILER, ST_FIND); 500 if (s != NULL && e->e_from.q_mailer != LocalMailer && 501 to->q_mailer == s->s_mailer) 502 { 503 usrerr("No ARPA mail through this machine: see your system administration"); 504 /* NoReturn = TRUE; to supress return copy */ 505 return (EX_UNAVAILABLE); 506 } 507 # endif /* EXAMPLE_CODE */ 508 return (EX_OK); 509 } 510 /* 511 ** HOLDSIGS -- arrange to hold all signals 512 ** 513 ** Parameters: 514 ** none. 515 ** 516 ** Returns: 517 ** none. 518 ** 519 ** Side Effects: 520 ** Arranges that signals are held. 521 */ 522 523 holdsigs() 524 { 525 } 526 /* 527 ** RLSESIGS -- arrange to release all signals 528 ** 529 ** This undoes the effect of holdsigs. 530 ** 531 ** Parameters: 532 ** none. 533 ** 534 ** Returns: 535 ** none. 536 ** 537 ** Side Effects: 538 ** Arranges that signals are released. 539 */ 540 541 rlsesigs() 542 { 543 } 544 /* 545 ** GETLA -- get the current load average 546 ** 547 ** This code stolen from la.c. 548 ** 549 ** Parameters: 550 ** none. 551 ** 552 ** Returns: 553 ** The current load average as an integer. 554 ** 555 ** Side Effects: 556 ** none. 557 */ 558 559 /* try to guess what style of load average we have */ 560 #define LA_ZERO 1 /* always return load average as zero */ 561 #define LA_INT 2 /* read kmem for avenrun; interpret as int */ 562 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 563 #define LA_SUBR 4 /* call getloadavg */ 564 565 #ifndef LA_TYPE 566 # if defined(sun) 567 # define LA_TYPE LA_INT 568 # endif 569 # if defined(mips) || defined(__alpha) 570 /* Ultrix or OSF/1 or RISC/os */ 571 # define LA_TYPE LA_INT 572 # define LA_AVENRUN "avenrun" 573 # endif 574 # if defined(hpux) 575 # define LA_TYPE LA_FLOAT 576 # endif 577 578 # ifndef LA_TYPE 579 # if defined(SYSTEM5) 580 # define LA_TYPE LA_INT 581 # define LA_AVENRUN "avenrun" 582 # else 583 # if defined(BSD) 584 # define LA_TYPE LA_SUBR 585 # else 586 # define LA_TYPE LA_ZERO 587 # endif 588 # endif 589 # endif 590 #endif 591 592 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) 593 594 #include <nlist.h> 595 #include <fcntl.h> 596 597 #ifndef LA_AVENRUN 598 #define LA_AVENRUN "_avenrun" 599 #endif 600 601 /* _PATH_UNIX should be defined in <paths.h> */ 602 #ifndef _PATH_UNIX 603 # if defined(hpux) 604 # define _PATH_UNIX "/hp-ux" 605 # endif 606 # if defined(mips) && !defined(ultrix) 607 /* powerful RISC/os */ 608 # define _PATH_UNIX "/unix" 609 # endif 610 # if defined(SYSTEM5) 611 # ifndef _PATH_UNIX 612 # define _PATH_UNIX "/unix" 613 # endif 614 # endif 615 # ifndef _PATH_UNIX 616 # define _PATH_UNIX "/vmunix" 617 # endif 618 #endif 619 620 struct nlist Nl[] = 621 { 622 { LA_AVENRUN }, 623 #define X_AVENRUN 0 624 { 0 }, 625 }; 626 627 #if defined(unixpc) 628 # define FSHIFT 5 629 #endif 630 631 #if defined(__alpha) 632 # define FSHIFT 10 633 #endif 634 635 #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 636 # define FSHIFT 8 637 #endif 638 #if (LA_TYPE == LA_INT) && !defined(FSCALE) 639 # define FSCALE (1 << FSHIFT) 640 #endif 641 642 getla() 643 { 644 static int kmem = -1; 645 #if LA_TYPE == LA_INT 646 long avenrun[3]; 647 #else 648 double avenrun[3]; 649 #endif 650 extern off_t lseek(); 651 extern char *errstring(); 652 extern int errno; 653 654 if (kmem < 0) 655 { 656 kmem = open("/dev/kmem", 0, 0); 657 if (kmem < 0) 658 { 659 if (tTd(3, 1)) 660 printf("getla: open(/dev/kmem): %s\n", 661 errstring(errno)); 662 return (-1); 663 } 664 (void) fcntl(kmem, F_SETFD, 1); 665 if (nlist(_PATH_UNIX, Nl) < 0) 666 { 667 if (tTd(3, 1)) 668 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 669 errstring(errno)); 670 return (-1); 671 } 672 } 673 if (tTd(3, 20)) 674 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 675 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 676 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 677 { 678 /* thank you Ian */ 679 if (tTd(3, 1)) 680 printf("getla: lseek or read: %s\n", errstring(errno)); 681 return (-1); 682 } 683 #if LA_TYPE == LA_INT 684 if (tTd(3, 5)) 685 { 686 printf("getla: avenrun = %d", avenrun[0]); 687 if (tTd(3, 15)) 688 printf(", %d, %d", avenrun[1], avenrun[2]); 689 printf("\n"); 690 } 691 if (tTd(3, 1)) 692 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 693 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 694 #else 695 if (tTd(3, 5)) 696 { 697 printf("getla: avenrun = %g", avenrun[0]); 698 if (tTd(3, 15)) 699 printf(", %g, %g", avenrun[1], avenrun[2]); 700 printf("\n"); 701 } 702 if (tTd(3, 1)) 703 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 704 return ((int) (avenrun[0] + 0.5)); 705 #endif 706 } 707 708 #else 709 #if LA_TYPE == LA_SUBR 710 711 getla() 712 { 713 double avenrun[3]; 714 715 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 716 { 717 if (tTd(3, 1)) 718 perror("getla: getloadavg failed:"); 719 return (-1); 720 } 721 if (tTd(3, 1)) 722 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 723 return ((int) (avenrun[0] + 0.5)); 724 } 725 726 #else 727 728 getla() 729 { 730 if (tTd(3, 1)) 731 printf("getla: ZERO\n"); 732 return (0); 733 } 734 735 #endif 736 #endif 737 /* 738 ** SHOULDQUEUE -- should this message be queued or sent? 739 ** 740 ** Compares the message cost to the load average to decide. 741 ** 742 ** Parameters: 743 ** pri -- the priority of the message in question. 744 ** ctime -- the message creation time. 745 ** 746 ** Returns: 747 ** TRUE -- if this message should be queued up for the 748 ** time being. 749 ** FALSE -- if the load is low enough to send this message. 750 ** 751 ** Side Effects: 752 ** none. 753 */ 754 755 bool 756 shouldqueue(pri, ctime) 757 long pri; 758 time_t ctime; 759 { 760 if (CurrentLA < QueueLA) 761 return (FALSE); 762 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 763 } 764 /* 765 ** REFUSECONNECTIONS -- decide if connections should be refused 766 ** 767 ** Parameters: 768 ** none. 769 ** 770 ** Returns: 771 ** TRUE if incoming SMTP connections should be refused 772 ** (for now). 773 ** FALSE if we should accept new work. 774 ** 775 ** Side Effects: 776 ** none. 777 */ 778 779 bool 780 refuseconnections() 781 { 782 /* this is probably too simplistic */ 783 return (CurrentLA > RefuseLA); 784 } 785 /* 786 ** SETPROCTITLE -- set process title for ps 787 ** 788 ** Parameters: 789 ** fmt -- a printf style format string. 790 ** a, b, c -- possible parameters to fmt. 791 ** 792 ** Returns: 793 ** none. 794 ** 795 ** Side Effects: 796 ** Clobbers argv of our main procedure so ps(1) will 797 ** display the title. 798 */ 799 800 /*VARARGS1*/ 801 #ifdef __STDC__ 802 setproctitle(char *fmt, ...) 803 #else 804 setproctitle(fmt, va_alist) 805 char *fmt; 806 va_dcl 807 #endif 808 { 809 # ifdef SETPROCTITLE 810 register char *p; 811 register int i; 812 char buf[MAXLINE]; 813 VA_LOCAL_DECL 814 extern char **Argv; 815 extern char *LastArgv; 816 817 p = buf; 818 819 /* print sendmail: heading for grep */ 820 (void) strcpy(p, "sendmail: "); 821 p += strlen(p); 822 823 /* print the argument string */ 824 VA_START(fmt); 825 (void) vsprintf(p, fmt, ap); 826 VA_END; 827 828 i = strlen(buf); 829 if (i > LastArgv - Argv[0] - 2) 830 { 831 i = LastArgv - Argv[0] - 2; 832 buf[i] = '\0'; 833 } 834 (void) strcpy(Argv[0], buf); 835 p = &Argv[0][i]; 836 while (p < LastArgv) 837 *p++ = ' '; 838 # endif /* SETPROCTITLE */ 839 } 840 /* 841 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 842 ** 843 ** Parameters: 844 ** none. 845 ** 846 ** Returns: 847 ** none. 848 ** 849 ** Side Effects: 850 ** Picks up extant zombies. 851 */ 852 853 # include <sys/wait.h> 854 855 void 856 reapchild() 857 { 858 # ifdef WNOHANG 859 union wait status; 860 861 while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 862 continue; 863 # else /* WNOHANG */ 864 auto int status; 865 866 while (wait((int *)&status) > 0) 867 continue; 868 # endif /* WNOHANG */ 869 # ifdef SYSTEM5 870 (void) signal(SIGCHLD, reapchild); 871 # endif 872 } 873 /* 874 ** UNSETENV -- remove a variable from the environment 875 ** 876 ** Not needed on newer systems. 877 ** 878 ** Parameters: 879 ** name -- the string name of the environment variable to be 880 ** deleted from the current environment. 881 ** 882 ** Returns: 883 ** none. 884 ** 885 ** Globals: 886 ** environ -- a pointer to the current environment. 887 ** 888 ** Side Effects: 889 ** Modifies environ. 890 */ 891 892 #ifdef UNSETENV 893 894 void 895 unsetenv(name) 896 char *name; 897 { 898 extern char **environ; 899 register char **pp; 900 int len = strlen(name); 901 902 for (pp = environ; *pp != NULL; pp++) 903 { 904 if (strncmp(name, *pp, len) == 0 && 905 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 906 break; 907 } 908 909 for (; *pp != NULL; pp++) 910 *pp = pp[1]; 911 } 912 913 #endif /* UNSETENV */ 914 /* 915 ** GETDTABLESIZE -- return number of file descriptors 916 ** 917 ** Only on non-BSD systems 918 ** 919 ** Parameters: 920 ** none 921 ** 922 ** Returns: 923 ** size of file descriptor table 924 ** 925 ** Side Effects: 926 ** none 927 */ 928 929 #ifdef SYSTEM5 930 931 int 932 getdtablesize() 933 { 934 return NOFILE; 935 } 936 937 #endif 938 /* 939 ** UNAME -- get the UUCP name of this system. 940 */ 941 942 #ifndef HASUNAME 943 944 int 945 uname(name) 946 struct utsname *name; 947 { 948 FILE *file; 949 char *n; 950 951 name->nodename[0] = '\0'; 952 953 /* try /etc/whoami -- one line with the node name */ 954 if ((file = fopen("/etc/whoami", "r")) != NULL) 955 { 956 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 957 (void) fclose(file); 958 n = strchr(name->nodename, '\n'); 959 if (n != NULL) 960 *n = '\0'; 961 if (name->nodename[0] != '\0') 962 return (0); 963 } 964 965 /* try /usr/include/whoami.h -- has a #define somewhere */ 966 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 967 { 968 char buf[MAXLINE]; 969 970 while (fgets(buf, MAXLINE, file) != NULL) 971 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 972 NODE_LENGTH, name->nodename) > 0) 973 break; 974 (void) fclose(file); 975 if (name->nodename[0] != '\0') 976 return (0); 977 } 978 979 #ifdef TRUST_POPEN 980 /* 981 ** Popen is known to have security holes. 982 */ 983 984 /* try uuname -l to return local name */ 985 if ((file = popen("uuname -l", "r")) != NULL) 986 { 987 (void) fgets(name, NODE_LENGTH + 1, file); 988 (void) pclose(file); 989 n = strchr(name, '\n'); 990 if (n != NULL) 991 *n = '\0'; 992 if (name->nodename[0] != '\0') 993 return (0); 994 } 995 #endif 996 997 return (-1); 998 } 999 #endif /* HASUNAME */ 1000 /* 1001 ** INITGROUPS -- initialize groups 1002 ** 1003 ** Stub implementation for System V style systems 1004 */ 1005 1006 #ifndef HASINITGROUPS 1007 # if !defined(SYSTEM5) || defined(hpux) 1008 # define HASINITGROUPS 1009 # endif 1010 #endif 1011 1012 #ifndef HASINITGROUPS 1013 1014 initgroups(name, basegid) 1015 char *name; 1016 int basegid; 1017 { 1018 return 0; 1019 } 1020 1021 #endif 1022 /* 1023 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1024 ** 1025 ** Only implemented if you have statfs. 1026 ** 1027 ** Parameters: 1028 ** none. 1029 ** 1030 ** Returns: 1031 ** TRUE if there is enough space. 1032 ** FALSE otherwise. 1033 */ 1034 1035 #ifndef HASSTATFS 1036 # if defined(BSD4_4) || defined(__osf__) 1037 # define HASSTATFS 1038 # endif 1039 #endif 1040 1041 #ifdef HASSTATFS 1042 #include <sys/mount.h> 1043 #endif 1044 1045 bool 1046 enoughspace() 1047 { 1048 #ifdef HASSTATFS 1049 struct statfs fs; 1050 extern int errno; 1051 extern char *errstring(); 1052 1053 if (MinBlocksFree > 0 && statfs(QueueDir, &fs) >= 0) 1054 { 1055 if (tTd(4, 80)) 1056 printf("enoughspace: bfree=%ld, min=%ld\n", 1057 fs.f_bfree, MinBlocksFree); 1058 if (fs.f_bfree < MinBlocksFree) 1059 return FALSE; 1060 } 1061 else if (tTd(4, 80)) 1062 printf("enoughspace: min=%ld: %s\n", 1063 MinBlocksFree, errstring(errno)); 1064 #endif 1065 return TRUE; 1066 } 1067