fix the System 5 compatilibility to be compatible with the rest
[unix-history] / usr / src / usr.sbin / sendmail / src / main.c
index ad72c28..9ec75bf 100644 (file)
@@ -1,10 +1,37 @@
-# define  _DEFINE
-# include <signal.h>
-# include <sys/ioctl.h>
-# include "sendmail.h"
-# include <sys/file.h>
-
-SCCSID(@(#)main.c      3.160           %G%);
+/*
+ * Copyright (c) 1983 Eric P. Allman
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c     6.13 (Berkeley) %G%";
+#endif /* not lint */
+
+#define        _DEFINE
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <sgtty.h>
+#include "sendmail.h"
+#ifdef NAMED_BIND
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif
+
+# ifdef lint
+char   edata, end;
+# endif lint
 
 /*
 **  SENDMAIL -- Post mail to a set of destinations.
 
 /*
 **  SENDMAIL -- Post mail to a set of destinations.
@@ -31,6 +58,7 @@ SCCSID(@(#)main.c     3.160           %G%);
 **             Eric Allman, UCB/INGRES (until 10/81)
 **                          Britton-Lee, Inc., purveyors of fine
 **                             database computers (from 11/81)
 **             Eric Allman, UCB/INGRES (until 10/81)
 **                          Britton-Lee, Inc., purveyors of fine
 **                             database computers (from 11/81)
+**                          Now back at UCB at the Mammoth project.
 **             The support of the INGRES Project and Britton-Lee is
 **                     gratefully acknowledged.  Britton-Lee in
 **                     particular had absolutely nothing to gain from
 **             The support of the INGRES Project and Britton-Lee is
 **                     gratefully acknowledged.  Britton-Lee in
 **                     particular had absolutely nothing to gain from
@@ -38,50 +66,84 @@ SCCSID(@(#)main.c   3.160           %G%);
 */
 
 
 */
 
 
-
-
-
-int            NextMailer = 0; /* "free" index into Mailer struct */
+int            NextMailer;     /* "free" index into Mailer struct */
 char           *FullName;      /* sender's full name */
 ENVELOPE       BlankEnvelope;  /* a "blank" envelope */
 ENVELOPE       MainEnvelope;   /* the envelope around the basic letter */
 char           *FullName;      /* sender's full name */
 ENVELOPE       BlankEnvelope;  /* a "blank" envelope */
 ENVELOPE       MainEnvelope;   /* the envelope around the basic letter */
+ADDRESS                NullAddress =   /* a null address */
+               { "", "", NULL, "" };
+char           *UserEnviron[MAXUSERENVIRON + 1];
+                               /* saved user environment */
 
 
-#ifdef DAEMON
-#ifndef SMTP
-ERROR %%%%   Cannot have daemon mode without SMTP   %%%% ERROR
-#endif SMTP
-#endif DAEMON
+/*
+**  Pointers for setproctitle.
+**     This allows "ps" listings to give more useful information.
+**     These must be kept out of BSS for frozen configuration files
+**             to work.
+*/
+
+# ifdef SETPROCTITLE
+char           **Argv = NULL;          /* pointer to argument vector */
+char           *LastArgv = NULL;       /* end of argv */
+# endif /* SETPROCTITLE */
 
 
+/*
+**  The file in which to log raw recipient information.
+**     This is logged before aliasing, forwarding, and so forth so we
+**     can see how our addresses are being used.  For example, this
+**     would give us the names of aliases (instead of what they alias
+**     to), the pre-MX hostnames, and so forth.
+**
+**     This is specified on the command line, not in the config file,
+**     and is therefore really only useful for logging SMTP RCPTs.
+*/
 
 
+char           *RcptLogFile = NULL;    /* file name */
 
 
+static void    obsolete();
 
 
+#ifdef DAEMON
+#ifndef SMTP
+ERROR %%%%   Cannot have daemon mode without SMTP   %%%% ERROR
+#endif /* SMTP */
+#endif /* DAEMON */
 
 
+#define MAXCONFIGLEVEL 3       /* highest config version level known */
 
 
-main(argc, argv)
+main(argc, argv, envp)
        int argc;
        char **argv;
        int argc;
        char **argv;
+       char **envp;
 {
        register char *p;
 {
        register char *p;
+       register char *q;
        char **av;
        char *locname;
        extern int finis();
        extern char Version[];
        char **av;
        char *locname;
        extern int finis();
        extern char Version[];
-       char *from;
+       char *ep, *from;
        typedef int (*fnptr)();
        STAB *st;
        register int i;
        typedef int (*fnptr)();
        STAB *st;
        register int i;
-       bool readconfig = FALSE;
-       bool safecf = TRUE;             /* this conf file is sys default */
+       int j;
+       bool readconfig = TRUE;
        bool queuemode = FALSE;         /* process queue requests */
        bool queuemode = FALSE;         /* process queue requests */
+       bool nothaw;
+       bool safecf = TRUE;
        static bool reenter = FALSE;
        static bool reenter = FALSE;
-       char jbuf[30];                  /* holds HostName */
+       char *argv0 = argv[0];
+       char jbuf[MAXHOSTNAMELEN];      /* holds MyHostName */
+       extern int DtableSize;
+       extern int optind;
        extern bool safefile();
        extern time_t convtime();
        extern putheader(), putbody();
        extern ENVELOPE *newenvelope();
        extern bool safefile();
        extern time_t convtime();
        extern putheader(), putbody();
        extern ENVELOPE *newenvelope();
-       extern intsig();
+       extern void intsig();
        extern char **myhostname();
        extern char *arpadate();
        extern char **myhostname();
        extern char *arpadate();
+       extern char *optarg;
+       extern char **environ;
 
        /*
        **  Check to see if we reentered.
 
        /*
        **  Check to see if we reentered.
@@ -98,14 +160,57 @@ main(argc, argv)
        extern ADDRESS *recipient();
        bool canrename;
 
        extern ADDRESS *recipient();
        bool canrename;
 
+#ifndef SYS5TZ
+       /* enforce use of kernel-supplied time zone information */
+       unsetenv("TZ");
+#endif
+
+       /* in 4.4BSD, the table can be huge; impose a reasonable limit */
+       DtableSize = getdtablesize();
+       if (DtableSize > 256)
+               DtableSize = 256;
+
        /*
        **  Be sure we have enough file descriptors.
        /*
        **  Be sure we have enough file descriptors.
+       **      But also be sure that 0, 1, & 2 are open.
        */
 
        */
 
-       for (i = 3; i < 20; i++)
-               (void) close(i);
+       i = open("/dev/null", O_RDWR);
+       while (i >= 0 && i < 2)
+               i = dup(i);
+
+       i = DtableSize;
+       while (--i > 0)
+       {
+               if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
+                       (void) close(i);
+       }
        errno = 0;
 
        errno = 0;
 
+#ifdef LOG_MAIL
+       openlog("sendmail", LOG_PID, LOG_MAIL);
+#else 
+       openlog("sendmail", LOG_PID);
+#endif 
+
+       /*
+       **  Set default values for variables.
+       **      These cannot be in initialized data space.
+       */
+
+       setdefaults();
+
+       /* set up the blank envelope */
+       BlankEnvelope.e_puthdr = putheader;
+       BlankEnvelope.e_putbody = putbody;
+       BlankEnvelope.e_xfp = NULL;
+       STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
+       STRUCTCOPY(BlankEnvelope, MainEnvelope);
+       CurEnv = &MainEnvelope;
+
+       /* Handle any non-getoptable constructions. */
+       obsolete(argv);
+
        /*
        **  Do a quick prescan of the argument list.
        **      We do this to find out if we can potentially thaw the
        /*
        **  Do a quick prescan of the argument list.
        **      We do this to find out if we can potentially thaw the
@@ -113,23 +218,66 @@ main(argc, argv)
        **      the argument processing applies to this run rather than
        **      to the run that froze the configuration.
        */
        **      the argument processing applies to this run rather than
        **      to the run that froze the configuration.
        */
-
-       argv[argc] = NULL;
-       av = argv;
-       while (*++av != NULL)
+       nothaw = FALSE;
+#define OPTIONS                "b:C:cd:e:F:f:h:Iimno:p:q:R:r:sTtv"
+       while ((j = getopt(argc, argv, OPTIONS)) != EOF)
        {
        {
-               if (strncmp(*av, "-C", 2) == 0 || strncmp(*av, "-bz", 3) == 0)
+               switch (j)
+               {
+                 case 'b':
+                       if (optarg[0] == 'z' && optarg[1] == '\0')
+                               nothaw = TRUE;
+                       break;
+
+                 case 'C':
+                       ConfFile = optarg;
+                       (void) setgid(getrgid());
+                       (void) setuid(getruid());
+                       safecf = FALSE;
+                       nothaw = TRUE;
                        break;
                        break;
+
+                 case 'd':
+                       tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
+                       tTflag(optarg);
+                       setbuf(stdout, (char *) NULL);
+                       printf("Version %s\n", Version);
+                       break;
+               }
        }
        }
-       if (*av == NULL)
-               readconfig = !thaw(FreezeFile);
 
 
+       InChannel = stdin;
+       OutChannel = stdout;
+
+       if (!nothaw)
+               readconfig = !thaw(FreezeFile, argv0);
+
+# ifdef SETPROCTITLE
        /*
        /*
-       **  Now do basic initialization
+       **  Move the environment so setproctitle can use the space at
+       **  the top of memory.
        */
 
        */
 
-       InChannel = stdin;
-       OutChannel = stdout;
+       for (i = j = 0; j < MAXUSERENVIRON && (p = envp[i]) != NULL; i++)
+       {
+               if (strncmp(p, "FS=", 3) == 0 || strncmp(p, "LD_", 3) == 0)
+                       continue;
+               UserEnviron[j++] = newstr(p);
+       }
+       UserEnviron[j] = NULL;
+       environ = UserEnviron;
+
+       /*
+       **  Save start and extent of argv for setproctitle.
+       */
+
+       Argv = argv;
+       if (i > 0)
+               LastArgv = envp[i - 1] + strlen(envp[i - 1]);
+       else
+               LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
+# endif /* SETPROCTITLE */
+
        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                (void) signal(SIGINT, intsig);
        if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                (void) signal(SIGINT, intsig);
        if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
@@ -139,41 +287,60 @@ main(argc, argv)
        OldUmask = umask(0);
        OpMode = MD_DELIVER;
        MotherPid = getpid();
        OldUmask = umask(0);
        OpMode = MD_DELIVER;
        MotherPid = getpid();
-# ifndef V6
        FullName = getenv("NAME");
        FullName = getenv("NAME");
-# endif V6
-
-       /* set up the blank envelope */
-       BlankEnvelope.e_puthdr = putheader;
-       BlankEnvelope.e_putbody = putbody;
-       BlankEnvelope.e_xfp = NULL;
-       CurEnv = &BlankEnvelope;
 
 
-       /* make sure we have a clean slate */
-       closeall();
-
-# ifdef LOG
-       openlog("sendmail", LOG_PID);
-# endif LOG
        errno = 0;
        from = NULL;
 
        errno = 0;
        from = NULL;
 
-       /* initialize some macros, etc. */
-       initmacros();
-
-       /* hostname */
-       av = myhostname(jbuf, sizeof jbuf);
-       if (jbuf[0] != '\0')
+       if (readconfig)
        {
        {
-               p = newstr(jbuf);
-               define('w', p, CurEnv);
-               setclass('w', p);
-       }
-       while (av != NULL && *av != NULL)
-               setclass('w', *av++);
+               /* initialize some macros, etc. */
+               initmacros();
 
 
-       /* version */
-       define('v', Version, CurEnv);
+               /* hostname */
+               av = myhostname(jbuf, sizeof jbuf);
+               if (jbuf[0] != '\0')
+               {
+                       struct  utsname utsname;
+                       extern char *strchr();
+
+                       if (tTd(0, 4))
+                               printf("canonical name: %s\n", jbuf);
+                       p = newstr(jbuf);
+                       define('w', p, CurEnv);
+
+                       q = strchr(jbuf, '.');
+                       if (q != NULL)
+                       {
+                               *q++ = '\0';
+                               p = newstr(jbuf);
+                               define('m', q, CurEnv);
+                       }
+                       setclass('w', p);
+
+                       if (uname(&utsname) >= 0)
+                               p = utsname.nodename;
+                       else
+                       {
+                               makelower(jbuf);
+                               p = jbuf;
+                       }
+                       if (tTd(0, 4))
+                               printf("UUCP nodename: %s\n", p);
+                       p = newstr(p);
+                       define('k', p, CurEnv);
+                       setclass('w', p);
+               }
+               while (av != NULL && *av != NULL)
+               {
+                       if (tTd(0, 4))
+                               printf("\ta.k.a.: %s\n", *av);
+                       setclass('w', *av++);
+               }
+
+               /* version */
+               define('v', Version, CurEnv);
+       }
 
        /* current time */
        define('b', arpadate((char *) NULL), CurEnv);
 
        /* current time */
        define('b', arpadate((char *) NULL), CurEnv);
@@ -183,103 +350,90 @@ main(argc, argv)
        */
 
        av = argv;
        */
 
        av = argv;
-       p = rindex(*av, '/');
+       p = strrchr(*av, '/');
        if (p++ == NULL)
                p = *av;
        if (strcmp(p, "newaliases") == 0)
                OpMode = MD_INITALIAS;
        else if (strcmp(p, "mailq") == 0)
                OpMode = MD_PRINT;
        if (p++ == NULL)
                p = *av;
        if (strcmp(p, "newaliases") == 0)
                OpMode = MD_INITALIAS;
        else if (strcmp(p, "mailq") == 0)
                OpMode = MD_PRINT;
-       while ((p = *++av) != NULL && p[0] == '-')
+       else if (strcmp(p, "smtpd") == 0)
+               OpMode = MD_DAEMON;
+
+       optind = 1;
+       while ((j = getopt(argc, argv, OPTIONS)) != EOF)
        {
        {
-               switch (p[1])
+               switch (j)
                {
                  case 'b':     /* operations mode */
                {
                  case 'b':     /* operations mode */
-                       switch (p[2])
+                       switch (j = *optarg)
                        {
                          case MD_DAEMON:
                        {
                          case MD_DAEMON:
-# ifndef DAEMON
-                               syserr("Daemon mode not implemented");
+# ifdef DAEMON
+                               if (getuid() != 0) {
+                                       usrerr("Permission denied");
+                                       exit (EX_USAGE);
+                               }
+                               (void) unsetenv("HOSTALIASES");
+# else
+                               usrerr("Daemon mode not implemented");
+                               ExitStat = EX_USAGE;
                                break;
                                break;
-# endif DAEMON
+# endif /* DAEMON */
                          case MD_SMTP:
 # ifndef SMTP
                          case MD_SMTP:
 # ifndef SMTP
-                               syserr("I don't speak SMTP");
+                               usrerr("I don't speak SMTP");
+                               ExitStat = EX_USAGE;
                                break;
                                break;
-# endif SMTP
-                         case MD_ARPAFTP:
+# endif /* SMTP */
                          case MD_DELIVER:
                          case MD_VERIFY:
                          case MD_TEST:
                          case MD_INITALIAS:
                          case MD_PRINT:
                          case MD_FREEZE:
                          case MD_DELIVER:
                          case MD_VERIFY:
                          case MD_TEST:
                          case MD_INITALIAS:
                          case MD_PRINT:
                          case MD_FREEZE:
-                               OpMode = p[2];
+                               OpMode = j;
                                break;
 
                          default:
                                break;
 
                          default:
-                               syserr("Invalid operation mode %c", p[2]);
+                               usrerr("Invalid operation mode %c", j);
+                               ExitStat = EX_USAGE;
                                break;
                        }
                        break;
 
                                break;
                        }
                        break;
 
-                 case 'C':     /* select configuration file */
-                       ConfFile = &p[2];
-                       if (ConfFile[0] == '\0')
-                               ConfFile = "sendmail.cf";
-                       safecf = FALSE;
+                 case 'C':     /* select configuration file (already done) */
                        break;
 
                        break;
 
-# ifdef DEBUG
-                 case 'd':     /* debug */
+                 case 'd':     /* debugging -- redo in case frozen */
                        tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
                        tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
-                       tTflag(&p[2]);
+                       tTflag(optarg);
                        setbuf(stdout, (char *) NULL);
                        setbuf(stdout, (char *) NULL);
-                       printf("Version %s\n", Version);
                        break;
                        break;
-# endif DEBUG
 
                  case 'f':     /* from address */
                  case 'r':     /* obsolete -f flag */
 
                  case 'f':     /* from address */
                  case 'r':     /* obsolete -f flag */
-                       p += 2;
-                       if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
-                       {
-                               p = *++av;
-                               if (p == NULL || *p == '-')
-                               {
-                                       syserr("No \"from\" person");
-                                       av--;
-                                       break;
-                               }
-                       }
                        if (from != NULL)
                        {
                        if (from != NULL)
                        {
-                               syserr("More than one \"from\" person");
+                               usrerr("More than one \"from\" person");
+                               ExitStat = EX_USAGE;
                                break;
                        }
                                break;
                        }
-                       from = p;
+                       from = newstr(optarg);
                        break;
 
                  case 'F':     /* set full name */
                        break;
 
                  case 'F':     /* set full name */
-                       p += 2;
-                       if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
-                       {
-                               syserr("Bad -F flag");
-                               av--;
-                               break;
-                       }
-                       FullName = p;
+                       FullName = newstr(optarg);
                        break;
 
                  case 'h':     /* hop count */
                        break;
 
                  case 'h':     /* hop count */
-                       p += 2;
-                       if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p)))
+                       CurEnv->e_hopcount = strtol(optarg, &ep, 10);
+                       if (*ep)
                        {
                        {
-                               syserr("Bad hop count (%s)", p);
-                               av--;
+                               usrerr("Bad hop count (%s)", optarg);
+                               ExitStat = EX_USAGE;
                                break;
                        }
                                break;
                        }
-                       CurEnv->e_hopcount = atoi(p);
                        break;
                
                  case 'n':     /* don't alias */
                        break;
                
                  case 'n':     /* don't alias */
@@ -287,16 +441,43 @@ main(argc, argv)
                        break;
 
                  case 'o':     /* set option */
                        break;
 
                  case 'o':     /* set option */
-                       setoption(p[2], &p[3], FALSE, TRUE);
+                       setoption(*optarg, optarg + 1, FALSE, TRUE);
+                       break;
+
+                 case 'p':     /* set protocol */
+                       q = strchr(optarg, ':');
+                       if (q != NULL)
+                               *q++ = '\0';
+                       if (*optarg != '\0')
+                               define('r', newstr(optarg), CurEnv);
+                       if (*q != '\0')
+                               define('s', newstr(q), CurEnv);
                        break;
 
                  case 'q':     /* run queue files at intervals */
 # ifdef QUEUE
                        break;
 
                  case 'q':     /* run queue files at intervals */
 # ifdef QUEUE
+                       if (getuid() != 0)
+                       {
+                               struct stat stbuf;
+
+                               /* check to see if we own the queue directory */
+                               if (stat(QueueDir, &stbuf) < 0)
+                                       syserr("main: cannot stat %s", QueueDir);
+                               if (stbuf.st_uid != getuid())
+                               {
+                                       /* nope, really a botch */
+                                       usrerr("Permission denied");
+                                       exit (EX_NOPERM);
+                               }
+                       }
+                       (void) unsetenv("HOSTALIASES");
+                       FullName = NULL;
                        queuemode = TRUE;
                        queuemode = TRUE;
-                       QueueIntvl = convtime(&p[2]);
-# else QUEUE
-                       syserr("I don't know about queues");
-# endif QUEUE
+                       QueueIntvl = convtime(optarg);
+# else /* QUEUE */
+                       usrerr("I don't know about queues");
+                       ExitStat = EX_USAGE;
+# endif /* QUEUE */
                        break;
 
                  case 't':     /* read recipients from message */
                        break;
 
                  case 't':     /* read recipients from message */
@@ -305,25 +486,43 @@ main(argc, argv)
 
                        /* compatibility flags */
                  case 'c':     /* connect to non-local mailers */
 
                        /* compatibility flags */
                  case 'c':     /* connect to non-local mailers */
-                 case 'e':     /* error message disposition */
                  case 'i':     /* don't let dot stop me */
                  case 'm':     /* send to me too */
                  case 'T':     /* set timeout interval */
                  case 'v':     /* give blow-by-blow description */
                  case 'i':     /* don't let dot stop me */
                  case 'm':     /* send to me too */
                  case 'T':     /* set timeout interval */
                  case 'v':     /* give blow-by-blow description */
-                       setoption(p[1], &p[2], FALSE, TRUE);
+                       setoption(j, "T", FALSE, TRUE);
+                       break;
+
+                 case 'e':     /* error message disposition */
+                       setoption(j, optarg, FALSE, TRUE);
                        break;
 
                  case 's':     /* save From lines in headers */
                        break;
 
                  case 's':     /* save From lines in headers */
-                       setoption('f', &p[2], FALSE, TRUE);
+                       setoption('f', "T", FALSE, TRUE);
                        break;
 
 # ifdef DBM
                  case 'I':     /* initialize alias DBM file */
                        OpMode = MD_INITALIAS;
                        break;
                        break;
 
 # ifdef DBM
                  case 'I':     /* initialize alias DBM file */
                        OpMode = MD_INITALIAS;
                        break;
-# endif DBM
+# endif /* DBM */
+
+                 case 'R':     /* log raw recipient info */
+                       RcptLogFile = newstr(optarg);
+                       break;
+
+                 default:
+                       ExitStat = EX_USAGE;
+                       finis();
+                       break;
                }
        }
                }
        }
+       av += optind;
+
+#ifdef NAMED_BIND
+       if (tTd(8, 1))
+               _res.options |= RES_DEBUG;
+#endif
 
        /*
        **  Do basic initialization.
 
        /*
        **  Do basic initialization.
@@ -331,18 +530,46 @@ main(argc, argv)
        **      Extract special fields for local use.
        */
 
        **      Extract special fields for local use.
        */
 
-       if (!safecf || OpMode == MD_FREEZE || readconfig)
-               readcf(ConfFile, safecf);
+       if (OpMode == MD_FREEZE || readconfig)
+               readcf(ConfFile, safecf, CurEnv);
+
+#ifdef SYS5TZ
+       /* Enforce use of local time (null string overrides this) */
+       if (TimeZoneSpec == NULL)
+               unsetenv("TZ");
+       else if (TimeZoneSpec[0] != '\0')
+       {
+               p = xalloc(strlen(TimeZoneSpec) + 4);
+               (void) strcpy(p, "TZ=");
+               (void) strcat(p, TimeZoneSpec);
+               putenv(p);
+       }
+#endif
 
 
+       if (ConfigLevel > MAXCONFIGLEVEL)
+       {
+               syserr("Warning: .cf version level (%d) exceeds program functionality (%d)",
+                       ConfigLevel, MAXCONFIGLEVEL);
+       }
        switch (OpMode)
        {
          case MD_FREEZE:
        switch (OpMode)
        {
          case MD_FREEZE:
+               /* this is critical to avoid forgeries of the frozen config */
+               (void) setgid(getgid());
+               (void) setuid(getuid());
+
+               /* freeze the configuration */
                freeze(FreezeFile);
                exit(EX_OK);
 
          case MD_INITALIAS:
                Verbose = TRUE;
                break;
                freeze(FreezeFile);
                exit(EX_OK);
 
          case MD_INITALIAS:
                Verbose = TRUE;
                break;
+
+         case MD_DAEMON:
+               /* remove things that don't make sense in daemon mode */
+               FullName = NULL;
+               break;
        }
 
        /* do heuristic mode adjustment */
        }
 
        /* do heuristic mode adjustment */
@@ -356,21 +583,35 @@ main(argc, argv)
        }
 
        /* our name for SMTP codes */
        }
 
        /* our name for SMTP codes */
-       expand("$j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
-       HostName = jbuf;
+       expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
+       MyHostName = jbuf;
 
 
-       /* the indices of local and program mailers */
+       /* the indices of built-in mailers */
        st = stab("local", ST_MAILER, ST_FIND);
        if (st == NULL)
                syserr("No local mailer defined");
        else
                LocalMailer = st->s_mailer;
        st = stab("local", ST_MAILER, ST_FIND);
        if (st == NULL)
                syserr("No local mailer defined");
        else
                LocalMailer = st->s_mailer;
+
        st = stab("prog", ST_MAILER, ST_FIND);
        if (st == NULL)
                syserr("No prog mailer defined");
        else
                ProgMailer = st->s_mailer;
 
        st = stab("prog", ST_MAILER, ST_FIND);
        if (st == NULL)
                syserr("No prog mailer defined");
        else
                ProgMailer = st->s_mailer;
 
+       st = stab("*file*", ST_MAILER, ST_FIND);
+       if (st == NULL)
+               syserr("No *file* mailer defined");
+       else
+               FileMailer = st->s_mailer;
+
+       st = stab("*include*", ST_MAILER, ST_FIND);
+       if (st == NULL)
+               syserr("No *include* mailer defined");
+       else
+               InclMailer = st->s_mailer;
+
+
        /* operate in queue directory */
        if (chdir(QueueDir) < 0)
        {
        /* operate in queue directory */
        if (chdir(QueueDir) < 0)
        {
@@ -379,30 +620,37 @@ main(argc, argv)
        }
 
        /*
        }
 
        /*
-       **  If printing the queue, go off and do that.
+       **  Do operation-mode-dependent initialization.
        */
 
        */
 
-       if (OpMode == MD_PRINT)
+       switch (OpMode)
        {
        {
+         case MD_PRINT:
+               /* print the queue */
 #ifdef QUEUE
                dropenvelope(CurEnv);
                printqueue();
                exit(EX_OK);
 #ifdef QUEUE
                dropenvelope(CurEnv);
                printqueue();
                exit(EX_OK);
-#else QUEUE
+#else /* QUEUE */
                usrerr("No queue to print");
                finis();
                usrerr("No queue to print");
                finis();
-#endif QUEUE
-       }
+#endif /* QUEUE */
 
 
-       /*
-       **  Initialize aliases.
-       */
-
-       initaliases(AliasFile, OpMode == MD_INITALIAS);
-       if (OpMode == MD_INITALIAS)
+         case MD_INITALIAS:
+               /* initialize alias database */
+               initaliases(AliasFile, TRUE, CurEnv);
                exit(EX_OK);
 
                exit(EX_OK);
 
-# ifdef DEBUG
+         case MD_DAEMON:
+               /* don't open alias database -- done in srvrsmtp */
+               break;
+
+         default:
+               /* open the alias database */
+               initaliases(AliasFile, FALSE, CurEnv);
+               break;
+       }
+
        if (tTd(0, 15))
        {
                /* print configuration table (or at least part of it) */
        if (tTd(0, 15))
        {
                /* print configuration table (or at least part of it) */
@@ -419,13 +667,24 @@ main(argc, argv)
                                m->m_maxsize);
                        for (j = '\0'; j <= '\177'; j++)
                                if (bitnset(j, m->m_flags))
                                m->m_maxsize);
                        for (j = '\0'; j <= '\177'; j++)
                                if (bitnset(j, m->m_flags))
-                                       putchar(j);
+                                       (void) putchar(j);
                        printf(" E=");
                        xputs(m->m_eol);
                        printf(" E=");
                        xputs(m->m_eol);
+                       if (m->m_argv != NULL)
+                       {
+                               char **a = m->m_argv;
+
+                               printf(" A=");
+                               while (*a != NULL)
+                               {
+                                       if (a != m->m_argv)
+                                               printf(" ");
+                                       xputs(*a++);
+                               }
+                       }
                        printf("\n");
                }
        }
                        printf("\n");
                }
        }
-# endif DEBUG
 
        /*
        **  Switch to the main envelope.
 
        /*
        **  Switch to the main envelope.
@@ -440,34 +699,51 @@ main(argc, argv)
 
        if (OpMode == MD_TEST)
        {
 
        if (OpMode == MD_TEST)
        {
+               bool terminal = isatty(fileno(stdin));
                char buf[MAXLINE];
 
                char buf[MAXLINE];
 
-               printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n");
+               if (terminal)
+               {
+                       printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
+                       printf("Enter <ruleset> <address>\n");
+               }
                for (;;)
                {
                        register char **pvp;
                        char *q;
                for (;;)
                {
                        register char **pvp;
                        char *q;
-                       extern char **prescan();
                        extern char *DelimChar;
                        extern char *DelimChar;
+                       extern bool invalidaddr();
 
 
-                       printf("> ");
-                       fflush(stdout);
+                       if (terminal)
+                               printf("> ");
+                       (void) fflush(stdout);
                        if (fgets(buf, sizeof buf, stdin) == NULL)
                                finis();
                        if (fgets(buf, sizeof buf, stdin) == NULL)
                                finis();
-                       for (p = buf; isspace(*p); *p++)
+                       if (!terminal)
+                               printf("> %s", buf);
+                       if (buf[0] == '#')
+                               continue;
+                       for (p = buf; isspace(*p); p++)
                                continue;
                        q = p;
                        while (*p != '\0' && !isspace(*p))
                                p++;
                        if (*p == '\0')
                                continue;
                        q = p;
                        while (*p != '\0' && !isspace(*p))
                                p++;
                        if (*p == '\0')
+                       {
+                               printf("No address!\n");
                                continue;
                                continue;
+                       }
                        *p = '\0';
                        *p = '\0';
+                       if (invalidaddr(p + 1))
+                               continue;
                        do
                        {
                        do
                        {
-                               pvp = prescan(++p, ',');
+                               extern char **prescan();
+                               char pvpbuf[PSBUFSIZE];
+
+                               pvp = prescan(++p, ',', pvpbuf);
                                if (pvp == NULL)
                                        continue;
                                if (pvp == NULL)
                                        continue;
-                               rewrite(pvp, 3);
                                p = q;
                                while (*p != '\0')
                                {
                                p = q;
                                while (*p != '\0')
                                {
@@ -489,7 +765,7 @@ main(argc, argv)
                runqueue(FALSE);
                finis();
        }
                runqueue(FALSE);
                finis();
        }
-# endif QUEUE
+# endif /* QUEUE */
 
        /*
        **  If a daemon, wait for a request.
 
        /*
        **  If a daemon, wait for a request.
@@ -526,7 +802,7 @@ main(argc, argv)
                                for (;;)
                                        pause();
                }
                                for (;;)
                                        pause();
                }
-# endif QUEUE
+# endif /* QUEUE */
                dropenvelope(CurEnv);
 
 #ifdef DAEMON
                dropenvelope(CurEnv);
 
 #ifdef DAEMON
@@ -536,7 +812,7 @@ main(argc, argv)
                OpMode = MD_SMTP;
                (void) newenvelope(CurEnv);
                openxscript(CurEnv);
                OpMode = MD_SMTP;
                (void) newenvelope(CurEnv);
                openxscript(CurEnv);
-#endif DAEMON
+#endif /* DAEMON */
        }
        
 # ifdef SMTP
        }
        
 # ifdef SMTP
@@ -546,19 +822,23 @@ main(argc, argv)
        */
 
        if (OpMode == MD_SMTP)
        */
 
        if (OpMode == MD_SMTP)
-               smtp();
-# endif SMTP
+               smtp(CurEnv);
+# endif /* SMTP */
 
        /*
        **  Do basic system initialization and set the sender
        */
 
 
        /*
        **  Do basic system initialization and set the sender
        */
 
-       initsys();
-       setsender(from);
+       initsys(CurEnv);
+       setsender(from, CurEnv);
 
 
-       if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo)
+       if (*av == NULL && !GrabTo)
        {
        {
-               usrerr("Usage: /etc/sendmail [flags] addr...");
+               usrerr("Recipient names must be specified");
+
+               /* collect body for UUCP return */
+               if (OpMode != MD_VERIFY)
+                       collect(FALSE, CurEnv);
                finis();
        }
        if (OpMode == MD_VERIFY)
                finis();
        }
        if (OpMode == MD_VERIFY)
@@ -568,7 +848,7 @@ main(argc, argv)
        **  Scan argv and deliver the message to everyone.
        */
 
        **  Scan argv and deliver the message to everyone.
        */
 
-       sendtoargv(av);
+       sendtoargv(av, CurEnv);
 
        /* if we have had errors sofar, arrange a meaningful exit stat */
        if (Errors > 0 && ExitStat == EX_OK)
 
        /* if we have had errors sofar, arrange a meaningful exit stat */
        if (Errors > 0 && ExitStat == EX_OK)
@@ -580,17 +860,15 @@ main(argc, argv)
 
        CurEnv->e_to = NULL;
        if (OpMode != MD_VERIFY || GrabTo)
 
        CurEnv->e_to = NULL;
        if (OpMode != MD_VERIFY || GrabTo)
-               collect(FALSE);
+               collect(FALSE, CurEnv);
        errno = 0;
 
        /* collect statistics */
        if (OpMode != MD_VERIFY)
                markstats(CurEnv, (ADDRESS *) NULL);
 
        errno = 0;
 
        /* collect statistics */
        if (OpMode != MD_VERIFY)
                markstats(CurEnv, (ADDRESS *) NULL);
 
-# ifdef DEBUG
        if (tTd(1, 1))
                printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
        if (tTd(1, 1))
                printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
-# endif DEBUG
 
        /*
        **  Actually send everything.
 
        /*
        **  Actually send everything.
@@ -598,8 +876,13 @@ main(argc, argv)
        */
 
        CurEnv->e_from.q_flags |= QDONTSEND;
        */
 
        CurEnv->e_from.q_flags |= QDONTSEND;
+       if (tTd(1, 5))
+       {
+               printf("main: QDONTSEND ");
+               printaddr(&CurEnv->e_from, FALSE);
+       }
        CurEnv->e_to = NULL;
        CurEnv->e_to = NULL;
-       sendall(CurEnv, SendMode);
+       sendall(CurEnv, SM_DEFAULT);
 
        /*
        ** All done.
 
        /*
        ** All done.
@@ -622,15 +905,16 @@ main(argc, argv)
 
 finis()
 {
 
 finis()
 {
-# ifdef DEBUG
        if (tTd(2, 1))
                printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);
        if (tTd(2, 1))
                printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);
-# endif DEBUG
 
        /* clean up temp files */
        CurEnv->e_to = NULL;
        dropenvelope(CurEnv);
 
 
        /* clean up temp files */
        CurEnv->e_to = NULL;
        dropenvelope(CurEnv);
 
+       /* flush any cached connections */
+       mci_flush();
+
        /* post statistics */
        poststats(StatFile);
 
        /* post statistics */
        poststats(StatFile);
 
@@ -638,7 +922,7 @@ finis()
 # ifdef LOG
        if (LogLevel > 11)
                syslog(LOG_DEBUG, "finis, pid=%d", getpid());
 # ifdef LOG
        if (LogLevel > 11)
                syslog(LOG_DEBUG, "finis, pid=%d", getpid());
-# endif LOG
+# endif /* LOG */
        if (ExitStat == EX_TEMPFAIL)
                ExitStat = EX_OK;
        exit(ExitStat);
        if (ExitStat == EX_TEMPFAIL)
                ExitStat = EX_OK;
        exit(ExitStat);
@@ -659,6 +943,7 @@ finis()
 **             Unlocks the current job.
 */
 
 **             Unlocks the current job.
 */
 
+void
 intsig()
 {
        FileName = NULL;
 intsig()
 {
        FileName = NULL;
@@ -681,23 +966,23 @@ intsig()
 **             initializes several macros to be themselves.
 */
 
 **             initializes several macros to be themselves.
 */
 
-struct metamac
-{
-       char    metaname;
-       char    metaval;
-};
-
 struct metamac MetaMacros[] =
 {
 struct metamac MetaMacros[] =
 {
-       /* these are important on the LHS */
-       '*', MATCHZANY, '+', MATCHANY,  '-', MATCHONE,  '=', MATCHCLASS,
-       '~', MATCHNCLASS,
+       /* LHS pattern matching characters */
+       '*', MATCHZANY,         '+', MATCHANY,          '-', MATCHONE,
+       '=', MATCHCLASS,        '~', MATCHNCLASS,
 
        /* these are RHS metasymbols */
 
        /* these are RHS metasymbols */
-       '#', CANONNET,  '@', CANONHOST, ':', CANONUSER, '>', CALLSUBR,
+       '#', CANONNET,          '@', CANONHOST,         ':', CANONUSER,
+       '>', CALLSUBR,
+       '{', MATCHLOOKUP,               '}', MATCHELOOKUP,
+
+       /* the conditional operations */
+       '?', CONDIF,            '|', CONDELSE,          '.', CONDFI,
 
 
-       /* and finally the conditional operations */
-       '?', CONDIF,    '|', CONDELSE,  '.', CONDFI,
+       /* and finally the hostname lookup characters */
+       '[', HOSTBEGIN,         ']', HOSTEND,
+       '(', LOOKUPBEGIN,       ')', LOOKUPEND,
 
        '\0'
 };
 
        '\0'
 };
@@ -744,6 +1029,8 @@ union frz
        {
                time_t  frzstamp;       /* timestamp on this freeze */
                char    *frzbrk;        /* the current break */
        {
                time_t  frzstamp;       /* timestamp on this freeze */
                char    *frzbrk;        /* the current break */
+               char    *frzedata;      /* address of edata */
+               char    *frzend;        /* address of end */
                char    frzver[252];    /* sendmail version */
        } frzinfo;
 };
                char    frzver[252];    /* sendmail version */
        } frzinfo;
 };
@@ -753,7 +1040,7 @@ freeze(freezefile)
 {
        int f;
        union frz fhdr;
 {
        int f;
        union frz fhdr;
-       extern char edata;
+       extern char edata, end;
        extern char *sbrk();
        extern char Version[];
 
        extern char *sbrk();
        extern char Version[];
 
@@ -764,7 +1051,7 @@ freeze(freezefile)
        f = creat(freezefile, FileMode);
        if (f < 0)
        {
        f = creat(freezefile, FileMode);
        if (f < 0)
        {
-               syserr("Cannot freeze");
+               syserr("Cannot freeze %s", freezefile);
                errno = 0;
                return;
        }
                errno = 0;
                return;
        }
@@ -772,14 +1059,16 @@ freeze(freezefile)
        /* build the freeze header */
        fhdr.frzinfo.frzstamp = curtime();
        fhdr.frzinfo.frzbrk = sbrk(0);
        /* build the freeze header */
        fhdr.frzinfo.frzstamp = curtime();
        fhdr.frzinfo.frzbrk = sbrk(0);
-       strcpy(fhdr.frzinfo.frzver, Version);
+       fhdr.frzinfo.frzedata = &edata;
+       fhdr.frzinfo.frzend = &end;
+       (void) strcpy(fhdr.frzinfo.frzver, Version);
 
        /* write out the freeze header */
        if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr ||
 
        /* write out the freeze header */
        if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr ||
-           write(f, (char *) &edata, fhdr.frzinfo.frzbrk - &edata) !=
-                                       (fhdr.frzinfo.frzbrk - &edata))
+           write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
+                                       (int) (fhdr.frzinfo.frzbrk - &edata))
        {
        {
-               syserr("Cannot freeze");
+               syserr("Cannot freeze %s", freezefile);
        }
 
        /* fine, clean up */
        }
 
        /* fine, clean up */
@@ -790,6 +1079,7 @@ freeze(freezefile)
 **
 **     Parameters:
 **             freezefile -- the name of the file to thaw from.
 **
 **     Parameters:
 **             freezefile -- the name of the file to thaw from.
+**             binfile -- the name of the sendmail binary (ok to guess).
 **
 **     Returns:
 **             TRUE if it successfully read the freeze file.
 **
 **     Returns:
 **             TRUE if it successfully read the freeze file.
@@ -799,13 +1089,20 @@ freeze(freezefile)
 **             reads freezefile in to BSS area.
 */
 
 **             reads freezefile in to BSS area.
 */
 
-thaw(freezefile)
+thaw(freezefile, binfile)
        char *freezefile;
        char *freezefile;
+       char *binfile;
 {
        int f;
 {
        int f;
+       register char *p;
        union frz fhdr;
        union frz fhdr;
-       extern char edata;
+       char hbuf[60];
+       struct stat fst, sst;
+       extern char edata, end;
        extern char Version[];
        extern char Version[];
+       extern caddr_t brk();
+       extern char **myhostname();
+       extern char *macvalue();
 
        if (freezefile == NULL)
                return (FALSE);
 
        if (freezefile == NULL)
                return (FALSE);
@@ -818,16 +1115,40 @@ thaw(freezefile)
                return (FALSE);
        }
 
                return (FALSE);
        }
 
+       if (fstat(f, &fst) < 0 || stat(ConfFile, &sst) < 0 ||
+           fst.st_mtime < sst.st_mtime)
+       {
+               syslog(LOG_WARNING, "Freeze file older than config file");
+               (void) close(f);
+               return (FALSE);
+       }
+
+       if (strchr(binfile, '/') != NULL && stat(binfile, &sst) == 0 &&
+           fst.st_mtime < sst.st_mtime)
+       {
+               syslog(LOG_WARNING, "Freeze file older than binary file");
+               (void) close(f);
+               return (FALSE);
+       }
+
        /* read in the header */
        /* read in the header */
-       if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr ||
+       if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr)
+       {
+               syslog(LOG_WARNING, "Cannot read frozen config file");
+               (void) close(f);
+               return (FALSE);
+       }
+       if (fhdr.frzinfo.frzedata != &edata ||
+           fhdr.frzinfo.frzend != &end ||
            strcmp(fhdr.frzinfo.frzver, Version) != 0)
        {
            strcmp(fhdr.frzinfo.frzver, Version) != 0)
        {
+               syslog(LOG_WARNING, "Wrong version of frozen config file");
                (void) close(f);
                return (FALSE);
        }
 
        /* arrange to have enough space */
                (void) close(f);
                return (FALSE);
        }
 
        /* arrange to have enough space */
-       if (brk(fhdr.frzinfo.frzbrk) < 0)
+       if (brk(fhdr.frzinfo.frzbrk) == (caddr_t) -1)
        {
                syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
                (void) close(f);
        {
                syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
                (void) close(f);
@@ -835,16 +1156,27 @@ thaw(freezefile)
        }
 
        /* now read in the freeze file */
        }
 
        /* now read in the freeze file */
-       if (read(f, (char *) &edata, fhdr.frzinfo.frzbrk - &edata) !=
-                                       (fhdr.frzinfo.frzbrk - &edata))
+       if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
+                                       (int) (fhdr.frzinfo.frzbrk - &edata))
        {
        {
+               syserr("Cannot read frozen config file");
                /* oops!  we have trashed memory..... */
                /* oops!  we have trashed memory..... */
-               write(2, "Cannot read freeze file\n", 24);
+               (void) write(2, "Cannot read freeze file\n", 24);
                _exit(EX_SOFTWARE);
        }
 
        (void) close(f);
                _exit(EX_SOFTWARE);
        }
 
        (void) close(f);
-       return (TRUE);
+
+       /* verify that the host name was correct on the freeze */
+       (void) myhostname(hbuf, sizeof hbuf);
+       p = macvalue('w', CurEnv);
+       if (p == NULL)
+               p = "";
+       if (strcmp(hbuf, macvalue('w', CurEnv)) == 0)
+               return (TRUE);
+       syslog(LOG_WARNING, "Hostname changed since freeze (%s => %s)",
+               p, hbuf);
+       return (FALSE);
 }
 \f/*
 **  DISCONNECT -- remove our connection with any foreground process
 }
 \f/*
 **  DISCONNECT -- remove our connection with any foreground process
@@ -869,7 +1201,6 @@ disconnect(fulldrop)
 {
        int fd;
 
 {
        int fd;
 
-#ifdef DEBUG
        if (tTd(52, 1))
                printf("disconnect: In %d Out %d\n", fileno(InChannel),
                                                fileno(OutChannel));
        if (tTd(52, 1))
                printf("disconnect: In %d Out %d\n", fileno(InChannel),
                                                fileno(OutChannel));
@@ -878,12 +1209,11 @@ disconnect(fulldrop)
                printf("don't\n");
                return;
        }
                printf("don't\n");
                return;
        }
-#endif DEBUG
 
        /* be sure we don't get nasty signals */
 
        /* be sure we don't get nasty signals */
-       signal(SIGHUP, SIG_IGN);
-       signal(SIGINT, SIG_IGN);
-       signal(SIGQUIT, SIG_IGN);
+       (void) signal(SIGHUP, SIG_IGN);
+       (void) signal(SIGINT, SIG_IGN);
+       (void) signal(SIGQUIT, SIG_IGN);
 
        /* we can't communicate with our caller, so.... */
        HoldErrs = TRUE;
 
        /* we can't communicate with our caller, so.... */
        HoldErrs = TRUE;
@@ -912,24 +1242,65 @@ disconnect(fulldrop)
        while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0)
                continue;
 
        while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0)
                continue;
 
-#ifdef TIOCNOTTY
        /* drop our controlling TTY completely if possible */
        if (fulldrop)
        {
        /* drop our controlling TTY completely if possible */
        if (fulldrop)
        {
+#ifdef SYSTEM5
+               (void) setpgrp();
+#else
+               (void) setsid();
+#endif
+#ifdef TIOCNOTTY
                fd = open("/dev/tty", 2);
                if (fd >= 0)
                {
                fd = open("/dev/tty", 2);
                if (fd >= 0)
                {
-                       (void) ioctl(fd, TIOCNOTTY, 0);
+                       (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
                        (void) close(fd);
                }
                        (void) close(fd);
                }
+               (void) setpgrp(0, 0);
+#endif /* TIOCNOTTY */
                errno = 0;
        }
                errno = 0;
        }
-#endif TIOCNOTTY
 
 # ifdef LOG
        if (LogLevel > 11)
                syslog(LOG_DEBUG, "in background, pid=%d", getpid());
 
 # ifdef LOG
        if (LogLevel > 11)
                syslog(LOG_DEBUG, "in background, pid=%d", getpid());
-# endif LOG
+# endif /* LOG */
 
        errno = 0;
 }
 
        errno = 0;
 }
+
+static void
+obsolete(argv)
+       char *argv[];
+{
+       char *ap;
+
+       while (ap = *++argv)
+       {
+               /* Return if "--" or not an option of any form. */
+               if (ap[0] != '-' || ap[1] == '-')
+                       return;
+
+               /* If -C doesn't have an argument, use sendmail.cf. */
+#define        __DEFPATH       "sendmail.cf"
+               if (ap[1] == 'C' && ap[2] == '\0' &&
+                   (argv[1] == NULL || argv[1][0] == '-'))
+               {
+                       *argv = xalloc(sizeof(__DEFPATH) + 2);
+                       argv[0][0] = '-';
+                       argv[0][1] = 'C';
+                       (void)strcpy(&argv[0][2], __DEFPATH);
+               }
+
+               /* If -q doesn't have an argument, run it once. */
+               if (ap[1] == 'q' && ap[2] == '\0' &&
+                   (argv[1] == NULL || argv[1][0] == '-'))
+                       *argv = "-q0";
+
+               /* if -d doesn't have an argument, use 0-99.1 */
+               if (ap[1] == 'd' && ap[2] == '\0' &&
+                   (argv[1] == NULL || argv[1][0] == '-'))
+                       *argv = "-d0-99.1";
+       }
+}