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.34 (Berkeley) 09/04/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 *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ 106 107 108 109 /* 110 ** Privacy values 111 */ 112 113 struct prival PrivacyValues[] = 114 { 115 "public", PRIV_PUBLIC, 116 "needmailhelo", PRIV_NEEDMAILHELO, 117 "needexpnhelo", PRIV_NEEDEXPNHELO, 118 "needvrfyhelo", PRIV_NEEDVRFYHELO, 119 "noexpn", PRIV_NOEXPN, 120 "novrfy", PRIV_NOVRFY, 121 "restrictmailq", PRIV_RESTRICTMAILQ, 122 "restrictqrun", PRIV_RESTRICTQRUN, 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 469 if (tTd(49, 1)) 470 printf("checkcompat(to=%s, from=%s)\n", 471 to->q_paddr, e->e_from.q_paddr); 472 473 # ifdef EXAMPLE_CODE 474 /* this code is intended as an example only */ 475 register STAB *s; 476 477 s = stab("arpa", ST_MAILER, ST_FIND); 478 if (s != NULL && e->e_from.q_mailer != LocalMailer && 479 to->q_mailer == s->s_mailer) 480 { 481 usrerr("553 No ARPA mail through this machine: see your system administration"); 482 /* NoReturn = TRUE; to supress return copy */ 483 return (EX_UNAVAILABLE); 484 } 485 # endif /* EXAMPLE_CODE */ 486 return (EX_OK); 487 } 488 /* 489 ** SETSIGNAL -- set a signal handler 490 ** 491 ** This is essentially old BSD "signal(3)". 492 */ 493 494 setsig_t 495 setsignal(sig, handler) 496 int sig; 497 setsig_t handler; 498 { 499 #if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE) 500 return signal(sig, handler); 501 #else 502 struct sigaction n, o; 503 504 bzero(&n, sizeof n); 505 n.sa_handler = handler; 506 if (sigaction(sig, &n, &o) < 0) 507 return SIG_ERR; 508 return o.sa_handler; 509 #endif 510 } 511 /* 512 ** HOLDSIGS -- arrange to hold all signals 513 ** 514 ** Parameters: 515 ** none. 516 ** 517 ** Returns: 518 ** none. 519 ** 520 ** Side Effects: 521 ** Arranges that signals are held. 522 */ 523 524 holdsigs() 525 { 526 } 527 /* 528 ** RLSESIGS -- arrange to release all signals 529 ** 530 ** This undoes the effect of holdsigs. 531 ** 532 ** Parameters: 533 ** none. 534 ** 535 ** Returns: 536 ** none. 537 ** 538 ** Side Effects: 539 ** Arranges that signals are released. 540 */ 541 542 rlsesigs() 543 { 544 } 545 /* 546 ** GETLA -- get the current load average 547 ** 548 ** This code stolen from la.c. 549 ** 550 ** Parameters: 551 ** none. 552 ** 553 ** Returns: 554 ** The current load average as an integer. 555 ** 556 ** Side Effects: 557 ** none. 558 */ 559 560 /* try to guess what style of load average we have */ 561 #define LA_ZERO 1 /* always return load average as zero */ 562 #define LA_INT 2 /* read kmem for avenrun; interpret as long */ 563 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 564 #define LA_SUBR 4 /* call getloadavg */ 565 #define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */ 566 #define LA_SHORT 6 /* read kmem for avenrun; interpret as short */ 567 568 /* do guesses based on general OS type */ 569 #ifndef LA_TYPE 570 # define LA_TYPE LA_ZERO 571 #endif 572 573 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) 574 575 #include <nlist.h> 576 577 #ifndef LA_AVENRUN 578 # ifdef SYSTEM5 579 # define LA_AVENRUN "avenrun" 580 # else 581 # define LA_AVENRUN "_avenrun" 582 # endif 583 #endif 584 585 /* _PATH_UNIX should be defined in <paths.h> */ 586 #ifndef _PATH_UNIX 587 # if defined(SYSTEM5) 588 # define _PATH_UNIX "/unix" 589 # else 590 # define _PATH_UNIX "/vmunix" 591 # endif 592 #endif 593 594 struct nlist Nl[] = 595 { 596 { LA_AVENRUN }, 597 #define X_AVENRUN 0 598 { 0 }, 599 }; 600 601 #ifndef FSHIFT 602 # if defined(unixpc) 603 # define FSHIFT 5 604 # endif 605 606 # if defined(__alpha) 607 # define FSHIFT 10 608 # endif 609 610 # if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 611 # define FSHIFT 8 612 # endif 613 #endif 614 615 #if ((LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)) && !defined(FSCALE) 616 # define FSCALE (1 << FSHIFT) 617 #endif 618 619 getla() 620 { 621 static int kmem = -1; 622 #if LA_TYPE == LA_INT 623 long avenrun[3]; 624 #else 625 # if LA_TYPE == LA_SHORT 626 short avenrun[3]; 627 # else 628 double avenrun[3]; 629 # endif 630 #endif 631 extern off_t lseek(); 632 extern int errno; 633 634 if (kmem < 0) 635 { 636 kmem = open("/dev/kmem", 0, 0); 637 if (kmem < 0) 638 { 639 if (tTd(3, 1)) 640 printf("getla: open(/dev/kmem): %s\n", 641 errstring(errno)); 642 return (-1); 643 } 644 (void) fcntl(kmem, F_SETFD, 1); 645 if (nlist(_PATH_UNIX, Nl) < 0) 646 { 647 if (tTd(3, 1)) 648 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 649 errstring(errno)); 650 return (-1); 651 } 652 if (Nl[X_AVENRUN].n_value == 0) 653 { 654 if (tTd(3, 1)) 655 printf("getla: nlist(%s, %s) ==> 0\n", 656 _PATH_UNIX, LA_AVENRUN); 657 return (-1); 658 } 659 } 660 if (tTd(3, 20)) 661 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 662 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 663 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 664 { 665 /* thank you Ian */ 666 if (tTd(3, 1)) 667 printf("getla: lseek or read: %s\n", errstring(errno)); 668 return (-1); 669 } 670 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 671 if (tTd(3, 5)) 672 { 673 printf("getla: avenrun = %d", avenrun[0]); 674 if (tTd(3, 15)) 675 printf(", %d, %d", avenrun[1], avenrun[2]); 676 printf("\n"); 677 } 678 if (tTd(3, 1)) 679 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 680 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 681 #else 682 if (tTd(3, 5)) 683 { 684 printf("getla: avenrun = %g", avenrun[0]); 685 if (tTd(3, 15)) 686 printf(", %g, %g", avenrun[1], avenrun[2]); 687 printf("\n"); 688 } 689 if (tTd(3, 1)) 690 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 691 return ((int) (avenrun[0] + 0.5)); 692 #endif 693 } 694 695 #else 696 #if LA_TYPE == LA_SUBR 697 698 getla() 699 { 700 double avenrun[3]; 701 702 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 703 { 704 if (tTd(3, 1)) 705 perror("getla: getloadavg failed:"); 706 return (-1); 707 } 708 if (tTd(3, 1)) 709 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 710 return ((int) (avenrun[0] + 0.5)); 711 } 712 713 #else 714 #if LA_TYPE == LA_MACH 715 716 /* 717 ** This has been tested on NeXT release 2.1. 718 */ 719 720 #include <mach.h> 721 722 getla() 723 { 724 processor_set_t default_set; 725 kern_return_t error; 726 unsigned int info_count; 727 struct processor_set_basic_info info; 728 host_t host; 729 730 error = processor_set_default(host_self(), &default_set); 731 if (error != KERN_SUCCESS) 732 return -1; 733 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 734 if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, 735 &host, (processor_set_info_t)&info, 736 &info_count) != KERN_SUCCESS) 737 { 738 return -1; 739 } 740 return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE; 741 } 742 743 744 #else 745 746 getla() 747 { 748 if (tTd(3, 1)) 749 printf("getla: ZERO\n"); 750 return (0); 751 } 752 753 #endif 754 #endif 755 #endif 756 /* 757 ** SHOULDQUEUE -- should this message be queued or sent? 758 ** 759 ** Compares the message cost to the load average to decide. 760 ** 761 ** Parameters: 762 ** pri -- the priority of the message in question. 763 ** ctime -- the message creation time. 764 ** 765 ** Returns: 766 ** TRUE -- if this message should be queued up for the 767 ** time being. 768 ** FALSE -- if the load is low enough to send this message. 769 ** 770 ** Side Effects: 771 ** none. 772 */ 773 774 bool 775 shouldqueue(pri, ctime) 776 long pri; 777 time_t ctime; 778 { 779 if (CurrentLA < QueueLA) 780 return (FALSE); 781 if (CurrentLA >= RefuseLA) 782 return (TRUE); 783 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 784 } 785 /* 786 ** REFUSECONNECTIONS -- decide if connections should be refused 787 ** 788 ** Parameters: 789 ** none. 790 ** 791 ** Returns: 792 ** TRUE if incoming SMTP connections should be refused 793 ** (for now). 794 ** FALSE if we should accept new work. 795 ** 796 ** Side Effects: 797 ** none. 798 */ 799 800 bool 801 refuseconnections() 802 { 803 #ifdef XLA 804 if (!xla_smtp_ok()) 805 return TRUE; 806 #endif 807 808 /* this is probably too simplistic */ 809 return (CurrentLA >= RefuseLA); 810 } 811 /* 812 ** SETPROCTITLE -- set process title for ps 813 ** 814 ** Parameters: 815 ** fmt -- a printf style format string. 816 ** a, b, c -- possible parameters to fmt. 817 ** 818 ** Returns: 819 ** none. 820 ** 821 ** Side Effects: 822 ** Clobbers argv of our main procedure so ps(1) will 823 ** display the title. 824 */ 825 826 #ifdef SETPROCTITLE 827 # ifdef __hpux 828 # include <sys/pstat.h> 829 # endif 830 # ifdef BSD4_4 831 # include <machine/vmparam.h> 832 # include <sys/exec.h> 833 # ifdef __bsdi__ 834 # undef PS_STRINGS /* BSDI 1.0 doesn't do PS_STRINGS as we expect */ 835 # endif 836 # ifdef PS_STRINGS 837 # define SETPROC_STATIC static 838 # endif 839 # endif 840 # ifndef SETPROC_STATIC 841 # define SETPROC_STATIC 842 # endif 843 #endif 844 845 /*VARARGS1*/ 846 #ifdef __STDC__ 847 setproctitle(char *fmt, ...) 848 #else 849 setproctitle(fmt, va_alist) 850 char *fmt; 851 va_dcl 852 #endif 853 { 854 # ifdef SETPROCTITLE 855 register char *p; 856 register int i; 857 SETPROC_STATIC char buf[MAXLINE]; 858 VA_LOCAL_DECL 859 # ifdef __hpux 860 union pstun pst; 861 # endif 862 extern char **Argv; 863 extern char *LastArgv; 864 865 p = buf; 866 867 /* print sendmail: heading for grep */ 868 (void) strcpy(p, "sendmail: "); 869 p += strlen(p); 870 871 /* print the argument string */ 872 VA_START(fmt); 873 (void) vsprintf(p, fmt, ap); 874 VA_END; 875 876 i = strlen(buf); 877 878 # ifdef __hpux 879 pst.pst_command = buf; 880 pstat(PSTAT_SETCMD, pst, i, 0, 0); 881 # else 882 # ifdef PS_STRINGS 883 PS_STRINGS->ps_nargvstr = 1; 884 PS_STRINGS->ps_argvstr = buf; 885 # else 886 if (i > LastArgv - Argv[0] - 2) 887 { 888 i = LastArgv - Argv[0] - 2; 889 buf[i] = '\0'; 890 } 891 (void) strcpy(Argv[0], buf); 892 p = &Argv[0][i]; 893 while (p < LastArgv) 894 *p++ = ' '; 895 # endif 896 # endif 897 # endif /* SETPROCTITLE */ 898 } 899 /* 900 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 901 ** 902 ** Parameters: 903 ** none. 904 ** 905 ** Returns: 906 ** none. 907 ** 908 ** Side Effects: 909 ** Picks up extant zombies. 910 */ 911 912 # include <sys/wait.h> 913 914 void 915 reapchild() 916 { 917 # ifdef HASWAITPID 918 auto int status; 919 int count; 920 int pid; 921 922 count = 0; 923 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 924 { 925 if (count++ > 1000) 926 { 927 syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", 928 pid, status); 929 break; 930 } 931 } 932 # else 933 # ifdef WNOHANG 934 union wait status; 935 936 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) 937 continue; 938 # else /* WNOHANG */ 939 auto int status; 940 941 while (wait(&status) > 0) 942 continue; 943 # endif /* WNOHANG */ 944 # endif 945 # ifdef SYS5SIGNALS 946 (void) setsignal(SIGCHLD, reapchild); 947 # endif 948 } 949 /* 950 ** UNSETENV -- remove a variable from the environment 951 ** 952 ** Not needed on newer systems. 953 ** 954 ** Parameters: 955 ** name -- the string name of the environment variable to be 956 ** deleted from the current environment. 957 ** 958 ** Returns: 959 ** none. 960 ** 961 ** Globals: 962 ** environ -- a pointer to the current environment. 963 ** 964 ** Side Effects: 965 ** Modifies environ. 966 */ 967 968 #ifndef HASUNSETENV 969 970 void 971 unsetenv(name) 972 char *name; 973 { 974 extern char **environ; 975 register char **pp; 976 int len = strlen(name); 977 978 for (pp = environ; *pp != NULL; pp++) 979 { 980 if (strncmp(name, *pp, len) == 0 && 981 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 982 break; 983 } 984 985 for (; *pp != NULL; pp++) 986 *pp = pp[1]; 987 } 988 989 #endif 990 /* 991 ** GETDTABLESIZE -- return number of file descriptors 992 ** 993 ** Only on non-BSD systems 994 ** 995 ** Parameters: 996 ** none 997 ** 998 ** Returns: 999 ** size of file descriptor table 1000 ** 1001 ** Side Effects: 1002 ** none 1003 */ 1004 1005 #ifdef SOLARIS 1006 # include <sys/resource.h> 1007 #endif 1008 1009 int 1010 getdtsize() 1011 { 1012 #ifdef RLIMIT_NOFILE 1013 struct rlimit rl; 1014 1015 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 1016 return rl.rlim_cur; 1017 #endif 1018 1019 # ifdef HASGETDTABLESIZE 1020 return getdtablesize(); 1021 # else 1022 # ifdef _SC_OPEN_MAX 1023 return sysconf(_SC_OPEN_MAX); 1024 # else 1025 return NOFILE; 1026 # endif 1027 # endif 1028 } 1029 /* 1030 ** UNAME -- get the UUCP name of this system. 1031 */ 1032 1033 #ifndef HASUNAME 1034 1035 int 1036 uname(name) 1037 struct utsname *name; 1038 { 1039 FILE *file; 1040 char *n; 1041 1042 name->nodename[0] = '\0'; 1043 1044 /* try /etc/whoami -- one line with the node name */ 1045 if ((file = fopen("/etc/whoami", "r")) != NULL) 1046 { 1047 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 1048 (void) fclose(file); 1049 n = strchr(name->nodename, '\n'); 1050 if (n != NULL) 1051 *n = '\0'; 1052 if (name->nodename[0] != '\0') 1053 return (0); 1054 } 1055 1056 /* try /usr/include/whoami.h -- has a #define somewhere */ 1057 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 1058 { 1059 char buf[MAXLINE]; 1060 1061 while (fgets(buf, MAXLINE, file) != NULL) 1062 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 1063 NODE_LENGTH, name->nodename) > 0) 1064 break; 1065 (void) fclose(file); 1066 if (name->nodename[0] != '\0') 1067 return (0); 1068 } 1069 1070 #ifdef TRUST_POPEN 1071 /* 1072 ** Popen is known to have security holes. 1073 */ 1074 1075 /* try uuname -l to return local name */ 1076 if ((file = popen("uuname -l", "r")) != NULL) 1077 { 1078 (void) fgets(name, NODE_LENGTH + 1, file); 1079 (void) pclose(file); 1080 n = strchr(name, '\n'); 1081 if (n != NULL) 1082 *n = '\0'; 1083 if (name->nodename[0] != '\0') 1084 return (0); 1085 } 1086 #endif 1087 1088 return (-1); 1089 } 1090 #endif /* HASUNAME */ 1091 /* 1092 ** INITGROUPS -- initialize groups 1093 ** 1094 ** Stub implementation for System V style systems 1095 */ 1096 1097 #ifndef HASINITGROUPS 1098 1099 initgroups(name, basegid) 1100 char *name; 1101 int basegid; 1102 { 1103 return 0; 1104 } 1105 1106 #endif 1107 /* 1108 ** SETSID -- set session id (for non-POSIX systems) 1109 */ 1110 1111 #ifndef HASSETSID 1112 1113 pid_t 1114 setsid __P ((void)) 1115 { 1116 #ifdef TIOCNOTTY 1117 int fd; 1118 1119 fd = open("/dev/tty", 2); 1120 if (fd >= 0) 1121 { 1122 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); 1123 (void) close(fd); 1124 } 1125 #endif /* TIOCNOTTY */ 1126 # ifdef SYSTEM5 1127 return setpgrp(); 1128 # else 1129 return setpgid(0, getpid()); 1130 # endif 1131 } 1132 1133 #endif 1134 /* 1135 ** GETOPT -- for old systems or systems with bogus implementations 1136 */ 1137 1138 #ifdef NEEDGETOPT 1139 1140 /* 1141 * Copyright (c) 1985 Regents of the University of California. 1142 * All rights reserved. The Berkeley software License Agreement 1143 * specifies the terms and conditions for redistribution. 1144 */ 1145 1146 1147 /* 1148 ** this version hacked to add `atend' flag to allow state machine 1149 ** to reset if invoked by the program to scan args for a 2nd time 1150 */ 1151 1152 #if defined(LIBC_SCCS) && !defined(lint) 1153 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 1154 #endif /* LIBC_SCCS and not lint */ 1155 1156 #include <stdio.h> 1157 1158 /* 1159 * get option letter from argument vector 1160 */ 1161 int opterr = 1, /* if error message should be printed */ 1162 optind = 1, /* index into parent argv vector */ 1163 optopt; /* character checked for validity */ 1164 char *optarg; /* argument associated with option */ 1165 1166 #define BADCH (int)'?' 1167 #define EMSG "" 1168 #define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \ 1169 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} 1170 1171 getopt(nargc,nargv,ostr) 1172 int nargc; 1173 char **nargv, 1174 *ostr; 1175 { 1176 static char *place = EMSG; /* option letter processing */ 1177 static char atend = 0; 1178 register char *oli; /* option letter list index */ 1179 1180 if (atend) { 1181 atend = 0; 1182 place = EMSG; 1183 } 1184 if(!*place) { /* update scanning pointer */ 1185 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 1186 atend++; 1187 return(EOF); 1188 } 1189 if (*place == '-') { /* found "--" */ 1190 ++optind; 1191 atend++; 1192 return(EOF); 1193 } 1194 } /* option letter okay? */ 1195 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { 1196 if (!*place) ++optind; 1197 tell(": illegal option -- "); 1198 } 1199 if (*++oli != ':') { /* don't need argument */ 1200 optarg = NULL; 1201 if (!*place) ++optind; 1202 } 1203 else { /* need an argument */ 1204 if (*place) optarg = place; /* no white space */ 1205 else if (nargc <= ++optind) { /* no arg */ 1206 place = EMSG; 1207 tell(": option requires an argument -- "); 1208 } 1209 else optarg = nargv[optind]; /* white space */ 1210 place = EMSG; 1211 ++optind; 1212 } 1213 return(optopt); /* dump back option letter */ 1214 } 1215 1216 #endif 1217 /* 1218 ** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version 1219 */ 1220 1221 #ifdef NEEDVPRINTF 1222 1223 #define MAXARG 16 1224 1225 vfprintf(fp, fmt, ap) 1226 FILE * fp; 1227 char * fmt; 1228 char ** ap; 1229 { 1230 char * bp[MAXARG]; 1231 int i = 0; 1232 1233 while (*ap && i < MAXARG) 1234 bp[i++] = *ap++; 1235 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3], 1236 bp[4], bp[5], bp[6], bp[7], 1237 bp[8], bp[9], bp[10], bp[11], 1238 bp[12], bp[13], bp[14], bp[15]); 1239 } 1240 1241 vsprintf(s, fmt, ap) 1242 char * s; 1243 char * fmt; 1244 char ** ap; 1245 { 1246 char * bp[MAXARG]; 1247 int i = 0; 1248 1249 while (*ap && i < MAXARG) 1250 bp[i++] = *ap++; 1251 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3], 1252 bp[4], bp[5], bp[6], bp[7], 1253 bp[8], bp[9], bp[10], bp[11], 1254 bp[12], bp[13], bp[14], bp[15]); 1255 } 1256 1257 #endif 1258 /* 1259 ** FREESPACE -- see how much free space is on the queue filesystem 1260 ** 1261 ** Only implemented if you have statfs. 1262 ** 1263 ** Parameters: 1264 ** dir -- the directory in question. 1265 ** bsize -- a variable into which the filesystem 1266 ** block size is stored. 1267 ** 1268 ** Returns: 1269 ** The number of bytes free on the queue filesystem. 1270 ** -1 if the statfs call fails. 1271 ** 1272 ** Side effects: 1273 ** Puts the filesystem block size into bsize. 1274 */ 1275 1276 #ifdef HASSTATFS 1277 # undef HASUSTAT 1278 #endif 1279 1280 #if defined(HASUSTAT) 1281 # include <ustat.h> 1282 #endif 1283 1284 #ifdef HASSTATFS 1285 # if defined(IRIX) || defined(apollo) || defined(_SCO_unix_) 1286 # include <sys/statfs.h> 1287 # else 1288 # if (defined(sun) && !defined(BSD)) || defined(__hpux) || defined(_CONVEX_SOURCE) || defined(NeXT) || defined(_AUX_SOURCE) 1289 # include <sys/vfs.h> 1290 # else 1291 # include <sys/mount.h> 1292 # endif 1293 # endif 1294 #endif 1295 1296 long 1297 freespace(dir, bsize) 1298 char *dir; 1299 long *bsize; 1300 { 1301 #if defined(HASSTATFS) || defined(HASUSTAT) 1302 # if defined(HASUSTAT) 1303 struct ustat fs; 1304 struct stat statbuf; 1305 # define FSBLOCKSIZE DEV_BSIZE 1306 # define f_bavail f_tfree 1307 # else 1308 # if defined(ultrix) 1309 struct fs_data fs; 1310 # define f_bavail fd_bfreen 1311 # define FSBLOCKSIZE fs.fd_bsize 1312 # else 1313 struct statfs fs; 1314 # define FSBLOCKSIZE fs.f_bsize 1315 # if defined(_SCO_unix_) || defined(IRIX) 1316 # define f_bavail f_bfree 1317 # endif 1318 # endif 1319 # endif 1320 extern int errno; 1321 1322 # if defined(HASUSTAT) 1323 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1324 # else 1325 # if defined(IRIX) || defined(apollo) 1326 if (statfs(dir, &fs, sizeof fs, 0) == 0) 1327 # else 1328 # if defined(ultrix) 1329 if (statfs(dir, &fs) > 0) 1330 # else 1331 if (statfs(dir, &fs) == 0) 1332 # endif 1333 # endif 1334 # endif 1335 { 1336 if (bsize != NULL) 1337 *bsize = FSBLOCKSIZE; 1338 return (fs.f_bavail); 1339 } 1340 #endif 1341 return (-1); 1342 } 1343 /* 1344 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1345 ** 1346 ** Only implemented if you have statfs. 1347 ** 1348 ** Parameters: 1349 ** msize -- the size to check against. If zero, we don't yet 1350 ** know how big the message will be, so just check for 1351 ** a "reasonable" amount. 1352 ** 1353 ** Returns: 1354 ** TRUE if there is enough space. 1355 ** FALSE otherwise. 1356 */ 1357 1358 bool 1359 enoughspace(msize) 1360 long msize; 1361 { 1362 long bfree, bsize; 1363 1364 if (MinBlocksFree <= 0 && msize <= 0) 1365 { 1366 if (tTd(4, 80)) 1367 printf("enoughspace: no threshold\n"); 1368 return TRUE; 1369 } 1370 1371 if ((bfree = freespace(QueueDir, &bsize)) >= 0) 1372 { 1373 if (tTd(4, 80)) 1374 printf("enoughspace: bavail=%ld, need=%ld\n", 1375 bfree, msize); 1376 1377 /* convert msize to block count */ 1378 msize = msize / bsize + 1; 1379 if (MinBlocksFree >= 0) 1380 msize += MinBlocksFree; 1381 1382 if (bfree < msize) 1383 { 1384 #ifdef LOG 1385 if (LogLevel > 0) 1386 syslog(LOG_ALERT, 1387 "%s: low on space (have %ld, %s needs %ld in %s)", 1388 CurEnv->e_id, bfree, 1389 CurHostName, msize, QueueDir); 1390 #endif 1391 return FALSE; 1392 } 1393 } 1394 else if (tTd(4, 80)) 1395 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1396 MinBlocksFree, msize, errstring(errno)); 1397 return TRUE; 1398 } 1399 /* 1400 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1401 ** 1402 ** This looks at an errno value and tells if this is likely to 1403 ** go away if retried later. 1404 ** 1405 ** Parameters: 1406 ** err -- the errno code to classify. 1407 ** 1408 ** Returns: 1409 ** TRUE if this is probably transient. 1410 ** FALSE otherwise. 1411 */ 1412 1413 bool 1414 transienterror(err) 1415 int err; 1416 { 1417 switch (err) 1418 { 1419 case EIO: /* I/O error */ 1420 case ENXIO: /* Device not configured */ 1421 case EAGAIN: /* Resource temporarily unavailable */ 1422 case ENOMEM: /* Cannot allocate memory */ 1423 case ENODEV: /* Operation not supported by device */ 1424 case ENFILE: /* Too many open files in system */ 1425 case EMFILE: /* Too many open files */ 1426 case ENOSPC: /* No space left on device */ 1427 #ifdef ETIMEDOUT 1428 case ETIMEDOUT: /* Connection timed out */ 1429 #endif 1430 #ifdef ESTALE 1431 case ESTALE: /* Stale NFS file handle */ 1432 #endif 1433 #ifdef ENETDOWN 1434 case ENETDOWN: /* Network is down */ 1435 #endif 1436 #ifdef ENETUNREACH 1437 case ENETUNREACH: /* Network is unreachable */ 1438 #endif 1439 #ifdef ENETRESET 1440 case ENETRESET: /* Network dropped connection on reset */ 1441 #endif 1442 #ifdef ECONNABORTED 1443 case ECONNABORTED: /* Software caused connection abort */ 1444 #endif 1445 #ifdef ECONNRESET 1446 case ECONNRESET: /* Connection reset by peer */ 1447 #endif 1448 #ifdef ENOBUFS 1449 case ENOBUFS: /* No buffer space available */ 1450 #endif 1451 #ifdef ESHUTDOWN 1452 case ESHUTDOWN: /* Can't send after socket shutdown */ 1453 #endif 1454 #ifdef ECONNREFUSED 1455 case ECONNREFUSED: /* Connection refused */ 1456 #endif 1457 #ifdef EHOSTDOWN 1458 case EHOSTDOWN: /* Host is down */ 1459 #endif 1460 #ifdef EHOSTUNREACH 1461 case EHOSTUNREACH: /* No route to host */ 1462 #endif 1463 #ifdef EDQUOT 1464 case EDQUOT: /* Disc quota exceeded */ 1465 #endif 1466 #ifdef EPROCLIM 1467 case EPROCLIM: /* Too many processes */ 1468 #endif 1469 #ifdef EUSERS 1470 case EUSERS: /* Too many users */ 1471 #endif 1472 #ifdef EDEADLK 1473 case EDEADLK: /* Resource deadlock avoided */ 1474 #endif 1475 #ifdef EISCONN 1476 case EISCONN: /* Socket already connected */ 1477 #endif 1478 #ifdef EINPROGRESS 1479 case EINPROGRESS: /* Operation now in progress */ 1480 #endif 1481 #ifdef EALREADY 1482 case EALREADY: /* Operation already in progress */ 1483 #endif 1484 #ifdef EADDRINUSE 1485 case EADDRINUSE: /* Address already in use */ 1486 #endif 1487 #ifdef EADDRNOTAVAIL 1488 case EADDRNOTAVAIL: /* Can't assign requested address */ 1489 #endif 1490 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 1491 case ENOSR: /* Out of streams resources */ 1492 #endif 1493 return TRUE; 1494 } 1495 1496 /* nope, must be permanent */ 1497 return FALSE; 1498 } 1499 /* 1500 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 1501 ** 1502 ** Parameters: 1503 ** fd -- the file descriptor of the file. 1504 ** filename -- the file name (for error messages). 1505 ** ext -- the filename extension. 1506 ** type -- type of the lock. Bits can be: 1507 ** LOCK_EX -- exclusive lock. 1508 ** LOCK_NB -- non-blocking. 1509 ** 1510 ** Returns: 1511 ** TRUE if the lock was acquired. 1512 ** FALSE otherwise. 1513 */ 1514 1515 bool 1516 lockfile(fd, filename, ext, type) 1517 int fd; 1518 char *filename; 1519 char *ext; 1520 int type; 1521 { 1522 # ifndef HASFLOCK 1523 int action; 1524 struct flock lfd; 1525 1526 if (ext == NULL) 1527 ext = ""; 1528 1529 bzero(&lfd, sizeof lfd); 1530 if (bitset(LOCK_UN, type)) 1531 lfd.l_type = F_UNLCK; 1532 else if (bitset(LOCK_EX, type)) 1533 lfd.l_type = F_WRLCK; 1534 else 1535 lfd.l_type = F_RDLCK; 1536 1537 if (bitset(LOCK_NB, type)) 1538 action = F_SETLK; 1539 else 1540 action = F_SETLKW; 1541 1542 if (tTd(55, 60)) 1543 printf("lockfile(%s%s, action=%d, type=%d): ", 1544 filename, ext, action, lfd.l_type); 1545 1546 if (fcntl(fd, action, &lfd) >= 0) 1547 { 1548 if (tTd(55, 60)) 1549 printf("SUCCESS\n"); 1550 return TRUE; 1551 } 1552 1553 if (tTd(55, 60)) 1554 printf("(%s) ", errstring(errno)); 1555 1556 /* 1557 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 1558 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 1559 ** as type "tmp" (that is, served from swap space), the 1560 ** previous fcntl will fail with "Invalid argument" errors. 1561 ** Since this is fairly common during testing, we will assume 1562 ** that this indicates that the lock is successfully grabbed. 1563 */ 1564 1565 if (errno == EINVAL) 1566 { 1567 if (tTd(55, 60)) 1568 printf("SUCCESS\n"); 1569 return TRUE; 1570 } 1571 1572 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 1573 { 1574 int omode = -1; 1575 # ifdef F_GETFL 1576 int oerrno = errno; 1577 1578 (void) fcntl(fd, F_GETFL, &omode); 1579 errno = oerrno; 1580 # endif 1581 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1582 filename, ext, fd, type, omode, geteuid()); 1583 } 1584 # else 1585 if (ext == NULL) 1586 ext = ""; 1587 1588 if (tTd(55, 60)) 1589 printf("lockfile(%s%s, type=%o): ", filename, ext, type); 1590 1591 if (flock(fd, type) >= 0) 1592 { 1593 if (tTd(55, 60)) 1594 printf("SUCCESS\n"); 1595 return TRUE; 1596 } 1597 1598 if (tTd(55, 60)) 1599 printf("(%s) ", errstring(errno)); 1600 1601 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 1602 { 1603 int omode = -1; 1604 # ifdef F_GETFL 1605 int oerrno = errno; 1606 1607 (void) fcntl(fd, F_GETFL, &omode); 1608 errno = oerrno; 1609 # endif 1610 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1611 filename, ext, fd, type, omode, geteuid()); 1612 } 1613 # endif 1614 if (tTd(55, 60)) 1615 printf("FAIL\n"); 1616 return FALSE; 1617 } 1618