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