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