|
|
1.1 root 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.3 9/5/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: /* this is critical to avoid forgeries of the frozen config */
338: setuid(getuid());
339: setgid(getgid());
340:
341: /* freeze the configuration */
342: freeze(FreezeFile);
343: exit(EX_OK);
344:
345: case MD_INITALIAS:
346: Verbose = TRUE;
347: break;
348: }
349:
350: /* do heuristic mode adjustment */
351: if (Verbose)
352: {
353: /* turn off noconnect option */
354: setoption('c', "F", TRUE, FALSE);
355:
356: /* turn on interactive delivery */
357: setoption('d', "", TRUE, FALSE);
358: }
359:
360: /* our name for SMTP codes */
361: expand("$j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
362: HostName = jbuf;
363:
364: /* the indices of local and program mailers */
365: st = stab("local", ST_MAILER, ST_FIND);
366: if (st == NULL)
367: syserr("No local mailer defined");
368: else
369: LocalMailer = st->s_mailer;
370: st = stab("prog", ST_MAILER, ST_FIND);
371: if (st == NULL)
372: syserr("No prog mailer defined");
373: else
374: ProgMailer = st->s_mailer;
375:
376: /* operate in queue directory */
377: if (chdir(QueueDir) < 0)
378: {
379: syserr("cannot chdir(%s)", QueueDir);
380: exit(EX_SOFTWARE);
381: }
382:
383: /*
384: ** If printing the queue, go off and do that.
385: */
386:
387: if (OpMode == MD_PRINT)
388: {
389: #ifdef QUEUE
390: dropenvelope(CurEnv);
391: printqueue();
392: exit(EX_OK);
393: #else QUEUE
394: usrerr("No queue to print");
395: finis();
396: #endif QUEUE
397: }
398:
399: /*
400: ** Initialize aliases.
401: */
402:
403: initaliases(AliasFile, OpMode == MD_INITALIAS);
404: if (OpMode == MD_INITALIAS)
405: exit(EX_OK);
406:
407: # ifdef DEBUG
408: if (tTd(0, 15))
409: {
410: /* print configuration table (or at least part of it) */
411: printrules();
412: for (i = 0; i < MAXMAILERS; i++)
413: {
414: register struct mailer *m = Mailer[i];
415: int j;
416:
417: if (m == NULL)
418: continue;
419: printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name,
420: m->m_mailer, m->m_s_rwset, m->m_r_rwset,
421: m->m_maxsize);
422: for (j = '\0'; j <= '\177'; j++)
423: if (bitnset(j, m->m_flags))
424: putchar(j);
425: printf(" E=");
426: xputs(m->m_eol);
427: printf("\n");
428: }
429: }
430: # endif DEBUG
431:
432: /*
433: ** Switch to the main envelope.
434: */
435:
436: CurEnv = newenvelope(&MainEnvelope);
437: MainEnvelope.e_flags = BlankEnvelope.e_flags;
438:
439: /*
440: ** If test mode, read addresses from stdin and process.
441: */
442:
443: if (OpMode == MD_TEST)
444: {
445: char buf[MAXLINE];
446:
447: printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n");
448: for (;;)
449: {
450: register char **pvp;
451: char *q;
452: extern char **prescan();
453: extern char *DelimChar;
454:
455: printf("> ");
456: fflush(stdout);
457: if (fgets(buf, sizeof buf, stdin) == NULL)
458: finis();
459: for (p = buf; isspace(*p); *p++)
460: continue;
461: q = p;
462: while (*p != '\0' && !isspace(*p))
463: p++;
464: if (*p == '\0')
465: continue;
466: *p = '\0';
467: do
468: {
469: pvp = prescan(++p, ',');
470: if (pvp == NULL)
471: continue;
472: rewrite(pvp, 3);
473: p = q;
474: while (*p != '\0')
475: {
476: rewrite(pvp, atoi(p));
477: while (*p != '\0' && *p++ != ',')
478: continue;
479: }
480: } while (*(p = DelimChar) != '\0');
481: }
482: }
483:
484: # ifdef QUEUE
485: /*
486: ** If collecting stuff from the queue, go start doing that.
487: */
488:
489: if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
490: {
491: runqueue(FALSE);
492: finis();
493: }
494: # endif QUEUE
495:
496: /*
497: ** If a daemon, wait for a request.
498: ** getrequests will always return in a child.
499: ** If we should also be processing the queue, start
500: ** doing it in background.
501: ** We check for any errors that might have happened
502: ** during startup.
503: */
504:
505: if (OpMode == MD_DAEMON || QueueIntvl != 0)
506: {
507: if (!tTd(0, 1))
508: {
509: /* put us in background */
510: i = fork();
511: if (i < 0)
512: syserr("daemon: cannot fork");
513: if (i != 0)
514: exit(0);
515:
516: /* get our pid right */
517: MotherPid = getpid();
518:
519: /* disconnect from our controlling tty */
520: disconnect(TRUE);
521: }
522:
523: # ifdef QUEUE
524: if (queuemode)
525: {
526: runqueue(TRUE);
527: if (OpMode != MD_DAEMON)
528: for (;;)
529: pause();
530: }
531: # endif QUEUE
532: dropenvelope(CurEnv);
533:
534: #ifdef DAEMON
535: getrequests();
536:
537: /* at this point we are in a child: reset state */
538: OpMode = MD_SMTP;
539: (void) newenvelope(CurEnv);
540: openxscript(CurEnv);
541: #endif DAEMON
542: }
543:
544: # ifdef SMTP
545: /*
546: ** If running SMTP protocol, start collecting and executing
547: ** commands. This will never return.
548: */
549:
550: if (OpMode == MD_SMTP)
551: smtp();
552: # endif SMTP
553:
554: /*
555: ** Do basic system initialization and set the sender
556: */
557:
558: initsys();
559: setsender(from);
560:
561: if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo)
562: {
563: usrerr("Usage: /etc/sendmail [flags] addr...");
564: finis();
565: }
566: if (OpMode == MD_VERIFY)
567: SendMode = SM_VERIFY;
568:
569: /*
570: ** Scan argv and deliver the message to everyone.
571: */
572:
573: sendtoargv(av);
574:
575: /* if we have had errors sofar, arrange a meaningful exit stat */
576: if (Errors > 0 && ExitStat == EX_OK)
577: ExitStat = EX_USAGE;
578:
579: /*
580: ** Read the input mail.
581: */
582:
583: CurEnv->e_to = NULL;
584: if (OpMode != MD_VERIFY || GrabTo)
585: collect(FALSE);
586: errno = 0;
587:
588: /* collect statistics */
589: if (OpMode != MD_VERIFY)
590: markstats(CurEnv, (ADDRESS *) NULL);
591:
592: # ifdef DEBUG
593: if (tTd(1, 1))
594: printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
595: # endif DEBUG
596:
597: /*
598: ** Actually send everything.
599: ** If verifying, just ack.
600: */
601:
602: CurEnv->e_from.q_flags |= QDONTSEND;
603: CurEnv->e_to = NULL;
604: sendall(CurEnv, SM_DEFAULT);
605:
606: /*
607: ** All done.
608: */
609:
610: finis();
611: }
612: /*
613: ** FINIS -- Clean up and exit.
614: **
615: ** Parameters:
616: ** none
617: **
618: ** Returns:
619: ** never
620: **
621: ** Side Effects:
622: ** exits sendmail
623: */
624:
625: finis()
626: {
627: # ifdef DEBUG
628: if (tTd(2, 1))
629: printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);
630: # endif DEBUG
631:
632: /* clean up temp files */
633: CurEnv->e_to = NULL;
634: dropenvelope(CurEnv);
635:
636: /* post statistics */
637: poststats(StatFile);
638:
639: /* and exit */
640: # ifdef LOG
641: if (LogLevel > 11)
642: syslog(LOG_DEBUG, "finis, pid=%d", getpid());
643: # endif LOG
644: if (ExitStat == EX_TEMPFAIL)
645: ExitStat = EX_OK;
646: exit(ExitStat);
647: }
648: /*
649: ** INTSIG -- clean up on interrupt
650: **
651: ** This just arranges to exit. It pessimises in that it
652: ** may resend a message.
653: **
654: ** Parameters:
655: ** none.
656: **
657: ** Returns:
658: ** none.
659: **
660: ** Side Effects:
661: ** Unlocks the current job.
662: */
663:
664: intsig()
665: {
666: FileName = NULL;
667: unlockqueue(CurEnv);
668: exit(EX_OK);
669: }
670: /*
671: ** INITMACROS -- initialize the macro system
672: **
673: ** This just involves defining some macros that are actually
674: ** used internally as metasymbols to be themselves.
675: **
676: ** Parameters:
677: ** none.
678: **
679: ** Returns:
680: ** none.
681: **
682: ** Side Effects:
683: ** initializes several macros to be themselves.
684: */
685:
686: struct metamac
687: {
688: char metaname;
689: char metaval;
690: };
691:
692: struct metamac MetaMacros[] =
693: {
694: /* these are important on the LHS */
695: '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE, '=', MATCHCLASS,
696: '~', MATCHNCLASS,
697:
698: /* these are RHS metasymbols */
699: '#', CANONNET, '@', CANONHOST, ':', CANONUSER, '>', CALLSUBR,
700:
701: /* and finally the conditional operations */
702: '?', CONDIF, '|', CONDELSE, '.', CONDFI,
703:
704: '\0'
705: };
706:
707: initmacros()
708: {
709: register struct metamac *m;
710: char buf[5];
711: register int c;
712:
713: for (m = MetaMacros; m->metaname != '\0'; m++)
714: {
715: buf[0] = m->metaval;
716: buf[1] = '\0';
717: define(m->metaname, newstr(buf), CurEnv);
718: }
719: buf[0] = MATCHREPL;
720: buf[2] = '\0';
721: for (c = '0'; c <= '9'; c++)
722: {
723: buf[1] = c;
724: define(c, newstr(buf), CurEnv);
725: }
726: }
727: /*
728: ** FREEZE -- freeze BSS & allocated memory
729: **
730: ** This will be used to efficiently load the configuration file.
731: **
732: ** Parameters:
733: ** freezefile -- the name of the file to freeze to.
734: **
735: ** Returns:
736: ** none.
737: **
738: ** Side Effects:
739: ** Writes BSS and malloc'ed memory to freezefile
740: */
741:
742: union frz
743: {
744: char frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */
745: struct
746: {
747: time_t frzstamp; /* timestamp on this freeze */
748: char *frzbrk; /* the current break */
749: char frzver[252]; /* sendmail version */
750: } frzinfo;
751: };
752:
753: freeze(freezefile)
754: char *freezefile;
755: {
756: int f;
757: union frz fhdr;
758: extern char edata;
759: extern char *sbrk();
760: extern char Version[];
761:
762: if (freezefile == NULL)
763: return;
764:
765: /* try to open the freeze file */
766: f = creat(freezefile, FileMode);
767: if (f < 0)
768: {
769: syserr("Cannot freeze");
770: errno = 0;
771: return;
772: }
773:
774: /* build the freeze header */
775: fhdr.frzinfo.frzstamp = curtime();
776: fhdr.frzinfo.frzbrk = sbrk(0);
777: strcpy(fhdr.frzinfo.frzver, Version);
778:
779: /* write out the freeze header */
780: if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr ||
781: write(f, (char *) &edata, fhdr.frzinfo.frzbrk - &edata) !=
782: (fhdr.frzinfo.frzbrk - &edata))
783: {
784: syserr("Cannot freeze");
785: }
786:
787: /* fine, clean up */
788: (void) close(f);
789: }
790: /*
791: ** THAW -- read in the frozen configuration file.
792: **
793: ** Parameters:
794: ** freezefile -- the name of the file to thaw from.
795: **
796: ** Returns:
797: ** TRUE if it successfully read the freeze file.
798: ** FALSE otherwise.
799: **
800: ** Side Effects:
801: ** reads freezefile in to BSS area.
802: */
803:
804: thaw(freezefile)
805: char *freezefile;
806: {
807: int f;
808: union frz fhdr;
809: extern char edata;
810: extern char Version[];
811:
812: if (freezefile == NULL)
813: return (FALSE);
814:
815: /* open the freeze file */
816: f = open(freezefile, 0);
817: if (f < 0)
818: {
819: errno = 0;
820: return (FALSE);
821: }
822:
823: /* read in the header */
824: if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr ||
825: strcmp(fhdr.frzinfo.frzver, Version) != 0)
826: {
827: (void) close(f);
828: return (FALSE);
829: }
830:
831: /* arrange to have enough space */
832: if (brk(fhdr.frzinfo.frzbrk) < 0)
833: {
834: syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
835: (void) close(f);
836: return (FALSE);
837: }
838:
839: /* now read in the freeze file */
840: if (read(f, (char *) &edata, fhdr.frzinfo.frzbrk - &edata) !=
841: (fhdr.frzinfo.frzbrk - &edata))
842: {
843: /* oops! we have trashed memory..... */
844: write(2, "Cannot read freeze file\n", 24);
845: _exit(EX_SOFTWARE);
846: }
847:
848: (void) close(f);
849: return (TRUE);
850: }
851: /*
852: ** DISCONNECT -- remove our connection with any foreground process
853: **
854: ** Parameters:
855: ** fulldrop -- if set, we should also drop the controlling
856: ** TTY if possible -- this should only be done when
857: ** setting up the daemon since otherwise UUCP can
858: ** leave us trying to open a dialin, and we will
859: ** wait for the carrier.
860: **
861: ** Returns:
862: ** none
863: **
864: ** Side Effects:
865: ** Trys to insure that we are immune to vagaries of
866: ** the controlling tty.
867: */
868:
869: disconnect(fulldrop)
870: bool fulldrop;
871: {
872: int fd;
873:
874: #ifdef DEBUG
875: if (tTd(52, 1))
876: printf("disconnect: In %d Out %d\n", fileno(InChannel),
877: fileno(OutChannel));
878: if (tTd(52, 5))
879: {
880: printf("don't\n");
881: return;
882: }
883: #endif DEBUG
884:
885: /* be sure we don't get nasty signals */
886: signal(SIGHUP, SIG_IGN);
887: signal(SIGINT, SIG_IGN);
888: signal(SIGQUIT, SIG_IGN);
889:
890: /* we can't communicate with our caller, so.... */
891: HoldErrs = TRUE;
892: ErrorMode = EM_MAIL;
893: Verbose = FALSE;
894:
895: /* all input from /dev/null */
896: if (InChannel != stdin)
897: {
898: (void) fclose(InChannel);
899: InChannel = stdin;
900: }
901: (void) freopen("/dev/null", "r", stdin);
902:
903: /* output to the transcript */
904: if (OutChannel != stdout)
905: {
906: (void) fclose(OutChannel);
907: OutChannel = stdout;
908: }
909: if (CurEnv->e_xfp == NULL)
910: CurEnv->e_xfp = fopen("/dev/null", "w");
911: (void) fflush(stdout);
912: (void) close(1);
913: (void) close(2);
914: while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0)
915: continue;
916:
917: #ifdef TIOCNOTTY
918: /* drop our controlling TTY completely if possible */
919: if (fulldrop)
920: {
921: fd = open("/dev/tty", 2);
922: if (fd >= 0)
923: {
924: (void) ioctl(fd, TIOCNOTTY, 0);
925: (void) close(fd);
926: }
927: errno = 0;
928: }
929: #endif TIOCNOTTY
930:
931: # ifdef LOG
932: if (LogLevel > 11)
933: syslog(LOG_DEBUG, "in background, pid=%d", getpid());
934: # endif LOG
935:
936: errno = 0;
937: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.