1: # define _DEFINE 2: # include <signal.h> 3: # include <sys/ioctl.h> 4: # include "sendmail.h" 5: # include <sys/file.h> 6: 7: SCCSID(@(#)main.c 4.2 8/28/83); 8: 9: /* 10: ** SENDMAIL -- Post mail to a set of destinations. 11: ** 12: ** This is the basic mail router. All user mail programs should 13: ** call this routine to actually deliver mail. Sendmail in 14: ** turn calls a bunch of mail servers that do the real work of 15: ** delivering the mail. 16: ** 17: ** Sendmail is driven by tables read in from /usr/lib/sendmail.cf 18: ** (read by readcf.c). Some more static configuration info, 19: ** including some code that you may want to tailor for your 20: ** installation, is in conf.c. You may also want to touch 21: ** daemon.c (if you have some other IPC mechanism), acct.c 22: ** (to change your accounting), names.c (to adjust the name 23: ** server mechanism). 24: ** 25: ** Usage: 26: ** /usr/lib/sendmail [flags] addr ... 27: ** 28: ** See the associated documentation for details. 29: ** 30: ** Author: 31: ** Eric Allman, UCB/INGRES (until 10/81) 32: ** Britton-Lee, Inc., purveyors of fine 33: ** database computers (from 11/81) 34: ** The support of the INGRES Project and Britton-Lee is 35: ** gratefully acknowledged. Britton-Lee in 36: ** particular had absolutely nothing to gain from 37: ** my involvement in this project. 38: */ 39: 40: 41: 42: 43: 44: int NextMailer = 0; /* "free" index into Mailer struct */ 45: char *FullName; /* sender's full name */ 46: ENVELOPE BlankEnvelope; /* a "blank" envelope */ 47: ENVELOPE MainEnvelope; /* the envelope around the basic letter */ 48: 49: #ifdef DAEMON 50: #ifndef SMTP 51: ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR 52: #endif SMTP 53: #endif DAEMON 54: 55: 56: 57: 58: 59: 60: main(argc, argv) 61: int argc; 62: char **argv; 63: { 64: register char *p; 65: char **av; 66: extern int finis(); 67: extern char Version[]; 68: char *from; 69: typedef int (*fnptr)(); 70: STAB *st; 71: register int i; 72: bool readconfig = FALSE; 73: bool safecf = TRUE; /* this conf file is sys default */ 74: bool queuemode = FALSE; /* process queue requests */ 75: static bool reenter = FALSE; 76: char jbuf[30]; /* holds HostName */ 77: extern bool safefile(); 78: extern time_t convtime(); 79: extern putheader(), putbody(); 80: extern ENVELOPE *newenvelope(); 81: extern intsig(); 82: extern char **myhostname(); 83: extern char *arpadate(); 84: 85: /* 86: ** Check to see if we reentered. 87: ** This would normally happen if e_putheader or e_putbody 88: ** were NULL when invoked. 89: */ 90: 91: if (reenter) 92: { 93: syserr("main: reentered!"); 94: abort(); 95: } 96: reenter = TRUE; 97: 98: /* 99: ** Be sure we have enough file descriptors. 100: */ 101: 102: for (i = 3; i < 20; i++) 103: (void) close(i); 104: errno = 0; 105: 106: /* 107: ** Do a quick prescan of the argument list. 108: ** We do this to find out if we can potentially thaw the 109: ** configuration file. If not, we do the thaw now so that 110: ** the argument processing applies to this run rather than 111: ** to the run that froze the configuration. 112: */ 113: 114: argv[argc] = NULL; 115: av = argv; 116: while (*++av != NULL) 117: { 118: if (strncmp(*av, "-C", 2) == 0 || strncmp(*av, "-bz", 3) == 0) 119: break; 120: } 121: if (*av == NULL) 122: readconfig = !thaw(FreezeFile); 123: 124: /* 125: ** Now do basic initialization 126: */ 127: 128: InChannel = stdin; 129: OutChannel = stdout; 130: if (signal(SIGINT, SIG_IGN) != SIG_IGN) 131: (void) signal(SIGINT, intsig); 132: if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 133: (void) signal(SIGHUP, intsig); 134: (void) signal(SIGTERM, intsig); 135: (void) signal(SIGPIPE, SIG_IGN); 136: OldUmask = umask(0); 137: OpMode = MD_DELIVER; 138: MotherPid = getpid(); 139: # ifndef V6 140: FullName = getenv("NAME"); 141: # endif V6 142: 143: /* set up the blank envelope */ 144: BlankEnvelope.e_puthdr = putheader; 145: BlankEnvelope.e_putbody = putbody; 146: BlankEnvelope.e_xfp = NULL; 147: CurEnv = &BlankEnvelope; 148: 149: /* make sure we have a clean slate */ 150: closeall(); 151: 152: # ifdef LOG 153: openlog("sendmail", LOG_PID); 154: # endif LOG 155: errno = 0; 156: from = NULL; 157: 158: /* initialize some macros, etc. */ 159: initmacros(); 160: 161: /* hostname */ 162: av = myhostname(jbuf, sizeof jbuf); 163: if (jbuf[0] != '\0') 164: { 165: p = newstr(jbuf); 166: define('w', p, CurEnv); 167: setclass('w', p); 168: } 169: while (av != NULL && *av != NULL) 170: setclass('w', *av++); 171: 172: /* version */ 173: define('v', Version, CurEnv); 174: 175: /* current time */ 176: define('b', arpadate((char *) NULL), CurEnv); 177: 178: /* 179: ** Crack argv. 180: */ 181: 182: av = argv; 183: p = rindex(*av, '/'); 184: if (p++ == NULL) 185: p = *av; 186: if (strcmp(p, "newaliases") == 0) 187: OpMode = MD_INITALIAS; 188: else if (strcmp(p, "mailq") == 0) 189: OpMode = MD_PRINT; 190: while ((p = *++av) != NULL && p[0] == '-') 191: { 192: switch (p[1]) 193: { 194: case 'b': /* operations mode */ 195: switch (p[2]) 196: { 197: case MD_DAEMON: 198: # ifndef DAEMON 199: syserr("Daemon mode not implemented"); 200: break; 201: # endif DAEMON 202: case MD_SMTP: 203: # ifndef SMTP 204: syserr("I don't speak SMTP"); 205: break; 206: # endif SMTP 207: case MD_ARPAFTP: 208: case MD_DELIVER: 209: case MD_VERIFY: 210: case MD_TEST: 211: case MD_INITALIAS: 212: case MD_PRINT: 213: case MD_FREEZE: 214: OpMode = p[2]; 215: break; 216: 217: default: 218: syserr("Invalid operation mode %c", p[2]); 219: break; 220: } 221: break; 222: 223: case 'C': /* select configuration file */ 224: ConfFile = &p[2]; 225: if (ConfFile[0] == '\0') 226: ConfFile = "sendmail.cf"; 227: safecf = FALSE; 228: break; 229: 230: # ifdef DEBUG 231: case 'd': /* debug */ 232: tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 233: tTflag(&p[2]); 234: setbuf(stdout, (char *) NULL); 235: printf("Version %s\n", Version); 236: break; 237: # endif DEBUG 238: 239: case 'f': /* from address */ 240: case 'r': /* obsolete -f flag */ 241: p += 2; 242: if (*p == '\0' && ((p = *++av) == NULL || *p == '-')) 243: { 244: p = *++av; 245: if (p == NULL || *p == '-') 246: { 247: syserr("No \"from\" person"); 248: av--; 249: break; 250: } 251: } 252: if (from != NULL) 253: { 254: syserr("More than one \"from\" person"); 255: break; 256: } 257: from = p; 258: break; 259: 260: case 'F': /* set full name */ 261: p += 2; 262: if (*p == '\0' && ((p = *++av) == NULL || *p == '-')) 263: { 264: syserr("Bad -F flag"); 265: av--; 266: break; 267: } 268: FullName = p; 269: break; 270: 271: case 'h': /* hop count */ 272: p += 2; 273: if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p))) 274: { 275: syserr("Bad hop count (%s)", p); 276: av--; 277: break; 278: } 279: CurEnv->e_hopcount = atoi(p); 280: break; 281: 282: case 'n': /* don't alias */ 283: NoAlias = TRUE; 284: break; 285: 286: case 'o': /* set option */ 287: setoption(p[2], &p[3], FALSE, TRUE); 288: break; 289: 290: case 'q': /* run queue files at intervals */ 291: # ifdef QUEUE 292: queuemode = TRUE; 293: QueueIntvl = convtime(&p[2]); 294: # else QUEUE 295: syserr("I don't know about queues"); 296: # endif QUEUE 297: break; 298: 299: case 't': /* read recipients from message */ 300: GrabTo = TRUE; 301: break; 302: 303: /* compatibility flags */ 304: case 'c': /* connect to non-local mailers */ 305: case 'e': /* error message disposition */ 306: case 'i': /* don't let dot stop me */ 307: case 'm': /* send to me too */ 308: case 'T': /* set timeout interval */ 309: case 'v': /* give blow-by-blow description */ 310: setoption(p[1], &p[2], FALSE, TRUE); 311: break; 312: 313: case 's': /* save From lines in headers */ 314: setoption('f', &p[2], FALSE, TRUE); 315: break; 316: 317: # ifdef DBM 318: case 'I': /* initialize alias DBM file */ 319: OpMode = MD_INITALIAS; 320: break; 321: # endif DBM 322: } 323: } 324: 325: /* 326: ** Do basic initialization. 327: ** Read system control file. 328: ** Extract special fields for local use. 329: */ 330: 331: if (!safecf || OpMode == MD_FREEZE || readconfig) 332: readcf(ConfFile, safecf); 333: 334: switch (OpMode) 335: { 336: case MD_FREEZE: 337: freeze(FreezeFile); 338: exit(EX_OK); 339: 340: case MD_INITALIAS: 341: Verbose = TRUE; 342: break; 343: } 344: 345: /* do heuristic mode adjustment */ 346: if (Verbose) 347: { 348: /* turn off noconnect option */ 349: setoption('c', "F", TRUE, FALSE); 350: 351: /* turn on interactive delivery */ 352: setoption('d', "", TRUE, FALSE); 353: } 354: 355: /* our name for SMTP codes */ 356: expand("$j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 357: HostName = jbuf; 358: 359: /* the indices of local and program mailers */ 360: st = stab("local", ST_MAILER, ST_FIND); 361: if (st == NULL) 362: syserr("No local mailer defined"); 363: else 364: LocalMailer = st->s_mailer; 365: st = stab("prog", ST_MAILER, ST_FIND); 366: if (st == NULL) 367: syserr("No prog mailer defined"); 368: else 369: ProgMailer = st->s_mailer; 370: 371: /* operate in queue directory */ 372: if (chdir(QueueDir) < 0) 373: { 374: syserr("cannot chdir(%s)", QueueDir); 375: exit(EX_SOFTWARE); 376: } 377: 378: /* 379: ** If printing the queue, go off and do that. 380: */ 381: 382: if (OpMode == MD_PRINT) 383: { 384: #ifdef QUEUE 385: dropenvelope(CurEnv); 386: printqueue(); 387: exit(EX_OK); 388: #else QUEUE 389: usrerr("No queue to print"); 390: finis(); 391: #endif QUEUE 392: } 393: 394: /* 395: ** Initialize aliases. 396: */ 397: 398: initaliases(AliasFile, OpMode == MD_INITALIAS); 399: if (OpMode == MD_INITALIAS) 400: exit(EX_OK); 401: 402: # ifdef DEBUG 403: if (tTd(0, 15)) 404: { 405: /* print configuration table (or at least part of it) */ 406: printrules(); 407: for (i = 0; i < MAXMAILERS; i++) 408: { 409: register struct mailer *m = Mailer[i]; 410: int j; 411: 412: if (m == NULL) 413: continue; 414: printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name, 415: m->m_mailer, m->m_s_rwset, m->m_r_rwset, 416: m->m_maxsize); 417: for (j = '\0'; j <= '\177'; j++) 418: if (bitnset(j, m->m_flags)) 419: putchar(j); 420: printf(" E="); 421: xputs(m->m_eol); 422: printf("\n"); 423: } 424: } 425: # endif DEBUG 426: 427: /* 428: ** Switch to the main envelope. 429: */ 430: 431: CurEnv = newenvelope(&MainEnvelope); 432: MainEnvelope.e_flags = BlankEnvelope.e_flags; 433: 434: /* 435: ** If test mode, read addresses from stdin and process. 436: */ 437: 438: if (OpMode == MD_TEST) 439: { 440: char buf[MAXLINE]; 441: 442: printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n"); 443: for (;;) 444: { 445: register char **pvp; 446: char *q; 447: extern char **prescan(); 448: extern char *DelimChar; 449: 450: printf("> "); 451: fflush(stdout); 452: if (fgets(buf, sizeof buf, stdin) == NULL) 453: finis(); 454: for (p = buf; isspace(*p); *p++) 455: continue; 456: q = p; 457: while (*p != '\0' && !isspace(*p)) 458: p++; 459: if (*p == '\0') 460: continue; 461: *p = '\0'; 462: do 463: { 464: pvp = prescan(++p, ','); 465: if (pvp == NULL) 466: continue; 467: rewrite(pvp, 3); 468: p = q; 469: while (*p != '\0') 470: { 471: rewrite(pvp, atoi(p)); 472: while (*p != '\0' && *p++ != ',') 473: continue; 474: } 475: } while (*(p = DelimChar) != '\0'); 476: } 477: } 478: 479: # ifdef QUEUE 480: /* 481: ** If collecting stuff from the queue, go start doing that. 482: */ 483: 484: if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) 485: { 486: runqueue(FALSE); 487: finis(); 488: } 489: # endif QUEUE 490: 491: /* 492: ** If a daemon, wait for a request. 493: ** getrequests will always return in a child. 494: ** If we should also be processing the queue, start 495: ** doing it in background. 496: ** We check for any errors that might have happened 497: ** during startup. 498: */ 499: 500: if (OpMode == MD_DAEMON || QueueIntvl != 0) 501: { 502: if (!tTd(0, 1)) 503: { 504: /* put us in background */ 505: i = fork(); 506: if (i < 0) 507: syserr("daemon: cannot fork"); 508: if (i != 0) 509: exit(0); 510: 511: /* get our pid right */ 512: MotherPid = getpid(); 513: 514: /* disconnect from our controlling tty */ 515: disconnect(TRUE); 516: } 517: 518: # ifdef QUEUE 519: if (queuemode) 520: { 521: runqueue(TRUE); 522: if (OpMode != MD_DAEMON) 523: for (;;) 524: pause(); 525: } 526: # endif QUEUE 527: dropenvelope(CurEnv); 528: 529: #ifdef DAEMON 530: getrequests(); 531: 532: /* at this point we are in a child: reset state */ 533: OpMode = MD_SMTP; 534: (void) newenvelope(CurEnv); 535: openxscript(CurEnv); 536: #endif DAEMON 537: } 538: 539: # ifdef SMTP 540: /* 541: ** If running SMTP protocol, start collecting and executing 542: ** commands. This will never return. 543: */ 544: 545: if (OpMode == MD_SMTP) 546: smtp(); 547: # endif SMTP 548: 549: /* 550: ** Do basic system initialization and set the sender 551: */ 552: 553: initsys(); 554: setsender(from); 555: 556: if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo) 557: { 558: usrerr("Usage: /etc/sendmail [flags] addr..."); 559: finis(); 560: } 561: if (OpMode == MD_VERIFY) 562: SendMode = SM_VERIFY; 563: 564: /* 565: ** Scan argv and deliver the message to everyone. 566: */ 567: 568: sendtoargv(av); 569: 570: /* if we have had errors sofar, arrange a meaningful exit stat */ 571: if (Errors > 0 && ExitStat == EX_OK) 572: ExitStat = EX_USAGE; 573: 574: /* 575: ** Read the input mail. 576: */ 577: 578: CurEnv->e_to = NULL; 579: if (OpMode != MD_VERIFY || GrabTo) 580: collect(FALSE); 581: errno = 0; 582: 583: /* collect statistics */ 584: if (OpMode != MD_VERIFY) 585: markstats(CurEnv, (ADDRESS *) NULL); 586: 587: # ifdef DEBUG 588: if (tTd(1, 1)) 589: printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr); 590: # endif DEBUG 591: 592: /* 593: ** Actually send everything. 594: ** If verifying, just ack. 595: */ 596: 597: CurEnv->e_from.q_flags |= QDONTSEND; 598: CurEnv->e_to = NULL; 599: sendall(CurEnv, SM_DEFAULT); 600: 601: /* 602: ** All done. 603: */ 604: 605: finis(); 606: } 607: /* 608: ** FINIS -- Clean up and exit. 609: ** 610: ** Parameters: 611: ** none 612: ** 613: ** Returns: 614: ** never 615: ** 616: ** Side Effects: 617: ** exits sendmail 618: */ 619: 620: finis() 621: { 622: # ifdef DEBUG 623: if (tTd(2, 1)) 624: printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags); 625: # endif DEBUG 626: 627: /* clean up temp files */ 628: CurEnv->e_to = NULL; 629: dropenvelope(CurEnv); 630: 631: /* post statistics */ 632: poststats(StatFile); 633: 634: /* and exit */ 635: # ifdef LOG 636: if (LogLevel > 11) 637: syslog(LOG_DEBUG, "finis, pid=%d", getpid()); 638: # endif LOG 639: if (ExitStat == EX_TEMPFAIL) 640: ExitStat = EX_OK; 641: exit(ExitStat); 642: } 643: /* 644: ** INTSIG -- clean up on interrupt 645: ** 646: ** This just arranges to exit. It pessimises in that it 647: ** may resend a message. 648: ** 649: ** Parameters: 650: ** none. 651: ** 652: ** Returns: 653: ** none. 654: ** 655: ** Side Effects: 656: ** Unlocks the current job. 657: */ 658: 659: intsig() 660: { 661: FileName = NULL; 662: unlockqueue(CurEnv); 663: exit(EX_OK); 664: } 665: /* 666: ** INITMACROS -- initialize the macro system 667: ** 668: ** This just involves defining some macros that are actually 669: ** used internally as metasymbols to be themselves. 670: ** 671: ** Parameters: 672: ** none. 673: ** 674: ** Returns: 675: ** none. 676: ** 677: ** Side Effects: 678: ** initializes several macros to be themselves. 679: */ 680: 681: struct metamac 682: { 683: char metaname; 684: char metaval; 685: }; 686: 687: struct metamac MetaMacros[] = 688: { 689: /* these are important on the LHS */ 690: '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE, '=', MATCHCLASS, 691: '~', MATCHNCLASS, 692: 693: /* these are RHS metasymbols */ 694: '#', CANONNET, '@', CANONHOST, ':', CANONUSER, '>', CALLSUBR, 695: 696: /* and finally the conditional operations */ 697: '?', CONDIF, '|', CONDELSE, '.', CONDFI, 698: 699: '\0' 700: }; 701: 702: initmacros() 703: { 704: register struct metamac *m; 705: char buf[5]; 706: register int c; 707: 708: for (m = MetaMacros; m->metaname != '\0'; m++) 709: { 710: buf[0] = m->metaval; 711: buf[1] = '\0'; 712: define(m->metaname, newstr(buf), CurEnv); 713: } 714: buf[0] = MATCHREPL; 715: buf[2] = '\0'; 716: for (c = '0'; c <= '9'; c++) 717: { 718: buf[1] = c; 719: define(c, newstr(buf), CurEnv); 720: } 721: } 722: /* 723: ** FREEZE -- freeze BSS & allocated memory 724: ** 725: ** This will be used to efficiently load the configuration file. 726: ** 727: ** Parameters: 728: ** freezefile -- the name of the file to freeze to. 729: ** 730: ** Returns: 731: ** none. 732: ** 733: ** Side Effects: 734: ** Writes BSS and malloc'ed memory to freezefile 735: */ 736: 737: union frz 738: { 739: char frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */ 740: struct 741: { 742: time_t frzstamp; /* timestamp on this freeze */ 743: char *frzbrk; /* the current break */ 744: char frzver[252]; /* sendmail version */ 745: } frzinfo; 746: }; 747: 748: freeze(freezefile) 749: char *freezefile; 750: { 751: int f; 752: union frz fhdr; 753: extern char edata; 754: extern char *sbrk(); 755: extern char Version[]; 756: 757: if (freezefile == NULL) 758: return; 759: 760: /* try to open the freeze file */ 761: f = creat(freezefile, FileMode); 762: if (f < 0) 763: { 764: syserr("Cannot freeze"); 765: errno = 0; 766: return; 767: } 768: 769: /* build the freeze header */ 770: fhdr.frzinfo.frzstamp = curtime(); 771: fhdr.frzinfo.frzbrk = sbrk(0); 772: strcpy(fhdr.frzinfo.frzver, Version); 773: 774: /* write out the freeze header */ 775: if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr || 776: write(f, (char *) &edata, fhdr.frzinfo.frzbrk - &edata) != 777: (fhdr.frzinfo.frzbrk - &edata)) 778: { 779: syserr("Cannot freeze"); 780: } 781: 782: /* fine, clean up */ 783: (void) close(f); 784: } 785: /* 786: ** THAW -- read in the frozen configuration file. 787: ** 788: ** Parameters: 789: ** freezefile -- the name of the file to thaw from. 790: ** 791: ** Returns: 792: ** TRUE if it successfully read the freeze file. 793: ** FALSE otherwise. 794: ** 795: ** Side Effects: 796: ** reads freezefile in to BSS area. 797: */ 798: 799: thaw(freezefile) 800: char *freezefile; 801: { 802: int f; 803: union frz fhdr; 804: extern char edata; 805: extern char Version[]; 806: 807: if (freezefile == NULL) 808: return (FALSE); 809: 810: /* open the freeze file */ 811: f = open(freezefile, 0); 812: if (f < 0) 813: { 814: errno = 0; 815: return (FALSE); 816: } 817: 818: /* read in the header */ 819: if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr || 820: strcmp(fhdr.frzinfo.frzver, Version) != 0) 821: { 822: (void) close(f); 823: return (FALSE); 824: } 825: 826: /* arrange to have enough space */ 827: if (brk(fhdr.frzinfo.frzbrk) < 0) 828: { 829: syserr("Cannot break to %x", fhdr.frzinfo.frzbrk); 830: (void) close(f); 831: return (FALSE); 832: } 833: 834: /* now read in the freeze file */ 835: if (read(f, (char *) &edata, fhdr.frzinfo.frzbrk - &edata) != 836: (fhdr.frzinfo.frzbrk - &edata)) 837: { 838: /* oops! we have trashed memory..... */ 839: write(2, "Cannot read freeze file\n", 24); 840: _exit(EX_SOFTWARE); 841: } 842: 843: (void) close(f); 844: return (TRUE); 845: } 846: /* 847: ** DISCONNECT -- remove our connection with any foreground process 848: ** 849: ** Parameters: 850: ** fulldrop -- if set, we should also drop the controlling 851: ** TTY if possible -- this should only be done when 852: ** setting up the daemon since otherwise UUCP can 853: ** leave us trying to open a dialin, and we will 854: ** wait for the carrier. 855: ** 856: ** Returns: 857: ** none 858: ** 859: ** Side Effects: 860: ** Trys to insure that we are immune to vagaries of 861: ** the controlling tty. 862: */ 863: 864: disconnect(fulldrop) 865: bool fulldrop; 866: { 867: int fd; 868: 869: #ifdef DEBUG 870: if (tTd(52, 1)) 871: printf("disconnect: In %d Out %d\n", fileno(InChannel), 872: fileno(OutChannel)); 873: if (tTd(52, 5)) 874: { 875: printf("don't\n"); 876: return; 877: } 878: #endif DEBUG 879: 880: /* be sure we don't get nasty signals */ 881: signal(SIGHUP, SIG_IGN); 882: signal(SIGINT, SIG_IGN); 883: signal(SIGQUIT, SIG_IGN); 884: 885: /* we can't communicate with our caller, so.... */ 886: HoldErrs = TRUE; 887: ErrorMode = EM_MAIL; 888: Verbose = FALSE; 889: 890: /* all input from /dev/null */ 891: if (InChannel != stdin) 892: { 893: (void) fclose(InChannel); 894: InChannel = stdin; 895: } 896: (void) freopen("/dev/null", "r", stdin); 897: 898: /* output to the transcript */ 899: if (OutChannel != stdout) 900: { 901: (void) fclose(OutChannel); 902: OutChannel = stdout; 903: } 904: if (CurEnv->e_xfp == NULL) 905: CurEnv->e_xfp = fopen("/dev/null", "w"); 906: (void) fflush(stdout); 907: (void) close(1); 908: (void) close(2); 909: while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0) 910: continue; 911: 912: #ifdef TIOCNOTTY 913: /* drop our controlling TTY completely if possible */ 914: if (fulldrop) 915: { 916: fd = open("/dev/tty", 2); 917: if (fd >= 0) 918: { 919: (void) ioctl(fd, TIOCNOTTY, 0); 920: (void) close(fd); 921: } 922: errno = 0; 923: } 924: #endif TIOCNOTTY 925: 926: # ifdef LOG 927: if (LogLevel > 11) 928: syslog(LOG_DEBUG, "in background, pid=%d", getpid()); 929: # endif LOG 930: 931: errno = 0; 932: }