home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / ek / eksw / src / main.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  21KB  |  641 lines

  1. typedef unsigned char uchar;
  2.  
  3. /*
  4.  * Embedded Kermit demo, main program.  
  5.  */
  6.  
  7. /*
  8.  * Author: Frank da Cruz, the Kermit Project, Columbia University, New
  9.  * York. Copyright (C) 1995, 2002, Trustees of Columbia University in the 
  10.  * City of New York. All rights reserved. 
  11.  * For license see kermit.c.
  12.  */
  13.  
  14. /*
  15.  * This is a demo/test framework, to be replaced by a real control
  16.  * program. It includes a simple Unix-style command-line parser to allow
  17.  * setup and testing of the Kermit module.  Skip past all this to where it 
  18.  * says REAL STUFF to see the real stuff.  ANSI C required.  Note: order
  19.  * of the following includes is important. 
  20.  */
  21.  
  22. #ifdef __linux
  23. #include <stdlib.h>             // for exit()
  24. #include <unistd.h>             // for access()
  25. #include <ctype.h>              // for isdigit()
  26. #include <errno.h>
  27. #endif /* __linux */
  28.  
  29. // handle name clash
  30. #ifdef X_OK
  31. #undef X_OK
  32. #endif
  33.  
  34. #include "cdefs.h"              /* Data types for all modules */
  35. #include "debug.h"              /* Debugging */
  36. #include "platform.h"           /* Platform-specific includes and
  37.                                  * definitions */
  38. #include "kermit.h"             /* Kermit symbols and data structures */
  39. #include "string.h"
  40.  
  41. /*
  42.  * Sample prototypes for i/o functions. The functions are defined in a
  43.  * platform-specific i/o module. The function names are unknown to the
  44.  * Kermit module. The names can be changed but not their calling
  45.  * conventions. The following prototypes are keyed to unixio.c. 
  46.  */
  47. int devopen (char *, long baud);        /* Communications device/path */
  48. int devsettings (char *);
  49. int devrestore (void);
  50. int devclose (void);
  51. int pktmode (short);
  52.  
  53. int readpkt (struct k_data *, UCHAR *, int);    /* Communications 
  54.                                                  * i/o functions */
  55. int tx_data (struct k_data *, UCHAR *, int);
  56. int inchk (struct k_data *);
  57.  
  58. int openfile (struct k_data *, UCHAR *, int);   /* File i/o
  59.                                                  * functions */
  60. int writefile (struct k_data *, UCHAR *, int);
  61. int readfile (struct k_data *);
  62. int closefile (struct k_data *, UCHAR, int);
  63. ULONG fileinfo (struct k_data *, UCHAR *, UCHAR *, int, short *, short);
  64.  
  65. /*
  66.  * External data 
  67.  */
  68.  
  69. extern UCHAR o_buf[];           /* Must be defined in io.c */
  70. extern UCHAR i_buf[];           /* Must be defined in io.c */
  71. extern int errno;
  72.  
  73. /*
  74.  * Data global to this module 
  75.  */
  76.  
  77. struct k_data k;                /* Kermit data structure */
  78. struct k_response r;            /* Kermit response structure */
  79.  
  80. char **xargv;                   /* Global pointer to arg vector */
  81. UCHAR **cmlist = (UCHAR **) 0;  /* Pointer to file list */
  82. char *xname = "eksw";           /* Default program name */
  83.  
  84. int xargc;                      /* Global argument count */
  85. int nfils = 0;                  /* Number of files in file list */
  86. int action = 0;                 /* Send or Receive */
  87. int xmode = 1;                  /* File-transfer mode */
  88. int ftype = 1;                  /* Global file type 0=text 1=binary */
  89. int keep = 0;                   /* Keep incompletely received files */
  90. int sync_server = 0;            /* Sync a server with E-pkt */
  91. int dbg = 0;                    /* Debugging */
  92. short fmode = -1;               /* Transfer mode for this file */
  93. int parity = 0;                 /* Parity */
  94. int check = 3;                  /* Block check */
  95. int remote = 1;                 /* 1 = Remote, 0 = Local */
  96.  
  97. #ifdef DEBUG
  98. int errorrate = 0;              /* Simulated error rate */
  99. int seed = 1234;                /* Random number generator seed */
  100. #endif /* DEBUG */
  101.  
  102. void
  103. doexit (int status)
  104. {
  105.    devrestore ();               /* Restore device */
  106.    devclose ();                 /* Close device */
  107.    exit (status);               /* Exit with indicated status */
  108. }
  109.  
  110. void
  111. usage ()
  112. {
  113.    fprintf (stderr, "E-Kermit %s\n", VERSION);
  114.    fprintf (stderr, "Usage: %s <options>\n", xname);
  115.    fprintf (stderr, "Options:\n");
  116.    fprintf (stderr, " -r           Receive files\n");
  117.    fprintf (stderr, " -g <files>   Get files\n");
  118.    fprintf (stderr, " -s <files>   Send files\n");
  119.    fprintf (stderr, " -w <number>  # of window slots\n");
  120.    fprintf (stderr, " -l <number>  packet length\n");
  121.    fprintf (stderr, " -p [neoms]   Parity: none, even, odd, mark, space\n");
  122.    fprintf (stderr, " -b [1235]     Block check type: 1, 2, 3 or 5\n");
  123.    fprintf (stderr, " -k           Keep incompletely received files\n");
  124.    fprintf (stderr, " -B           Force binary mode\n");
  125.    fprintf (stderr, " -T           Force text mode\n");
  126.    fprintf (stderr, " -R           Remote mode (vs local)\n");
  127.    fprintf (stderr, " -L           Local mode (vs remote)\n");
  128. #ifdef DEBUG
  129.    fprintf (stderr, " -E <number>  Simulated error rate (0-100)\n");
  130.    fprintf (stderr, " -d           debugging output to \"debug.log\"\n");
  131. #endif /* DEBUG */
  132.    fprintf (stderr, " -S           Synchronize a kermit server\n");
  133.    fprintf (stderr, " -h           Help (this message)\n");
  134.    doexit (FAILURE);
  135. }
  136.  
  137. void static
  138. fatal (char *msg1, char *msg2, char *msg3)
  139. {                               /* Not to be called except */
  140.    if (msg1)
  141.    {                            /* from this module */
  142.       fprintf (stderr, "%s: %s", xname, msg1);
  143.       if (msg2)
  144.          fprintf (stderr, "%s", msg2);
  145.       if (msg3)
  146.          fprintf (stderr, "%s", msg3);
  147.       fprintf (stderr, "\n");
  148.    }
  149.    doexit (FAILURE);
  150. }
  151.  
  152. /*
  153.  * Simple user interface for testing 
  154.  */
  155.  
  156. int
  157. doarg (char c)
  158. {                               /* Command-line option parser */
  159.    int x;                       /* Parses one option with its arg(s) */
  160.    char *xp, *s;
  161.    struct stat statbuf;
  162.  
  163.    xp = *xargv + 1;             /* Pointer for bundled args */
  164.    while (c)
  165.    {
  166. #ifdef DEBUG
  167.       if (errorrate)
  168.          seed += (int) c;
  169. #endif /* DEBUG) */
  170.       switch (c)
  171.       {
  172.       case 'r':                /* Receive */
  173.          if (action)
  174.             fatal ("Conflicting actions", (char *) 0, (char *) 0);
  175.          action = A_RECV;
  176.          break;
  177.  
  178.       case 'g':                /* Get */
  179.          if (action)
  180.             fatal ("Conflicting actions", (char *) 0, (char *) 0);
  181.          if (*(xp + 1))
  182.             fatal ("Invalid argument bundling after -g", (char *) 0,
  183.                    (char *) 0);
  184.          nfils = 0;             /* Initialize file counter, flag */
  185.          cmlist = (UCHAR **) (xargv + 1);       /* Remember this pointer */
  186.          while (--xargc > 0)
  187.          {                      /* Traverse the list */
  188.             xargv++;
  189.             s = *xargv;
  190. #ifdef DEBUG
  191.             if (errorrate)
  192.                seed += (int) *s;
  193. #endif /* DEBUG) */
  194.             if (**xargv == '-')
  195.                break;
  196.             errno = 0;
  197.             nfils++;
  198.          }
  199.          xargc++;
  200.          xargv--;               /* Adjust argv/argc */
  201.          if (nfils < 1)
  202.             fatal ("Missing filename for -g", (char *) 0, (char *) 0);
  203.          action = A_GET;
  204.          break;
  205.  
  206.       case 's':                /* Send */
  207.          if (action)
  208.             fatal ("Conflicting actions", (char *) 0, (char *) 0);
  209.          if (*(xp + 1))
  210.             fatal ("Invalid argument bundling after -s", (char *) 0,
  211.                    (char *) 0);
  212.          nfils = 0;             /* Initialize file counter, flag */
  213.          cmlist = (UCHAR **) (xargv + 1);       /* Remember this pointer */
  214.          while (--xargc > 0)
  215.          {                      /* Traverse the list */
  216.             xargv++;
  217.             s = *xargv;
  218. #ifdef DEBUG
  219.             if (errorrate)
  220.                seed += (int) *s;
  221. #endif /* DEBUG) */
  222.             if (**xargv == '-')
  223.                break;
  224.             errno = 0;
  225.             x = stat (s, &statbuf);
  226.             if (x < 0)
  227.                fatal ("File '", s, "' not found");
  228.             if (access (s, 4) < 0)
  229.                fatal ("File '", s, "' not accessible");
  230.             nfils++;
  231.          }
  232.          xargc++;
  233.          xargv--;               /* Adjust argv/argc */
  234.          if (nfils < 1)
  235.             fatal ("Missing filename for -s", (char *) 0, (char *) 0);
  236.          action = A_SEND;
  237.          break;
  238.  
  239.       case 'b':                /* Block-check type */
  240. #ifdef DEBUG
  241.       case 'E':                /* Simulated error rate */
  242. #endif /* DEBUG */
  243.       case 'w':                /* max window slots */
  244.       case 'l':                /* max packet length */
  245.          if (*(xp + 1))
  246.             fatal ("Invalid argument bundling", (char *) 0, (char *) 0);
  247.          xargv++, xargc--;
  248.          if ((xargc < 1) || (**xargv == '-'))
  249.             fatal ("Missing option argument", (char *) 0, (char *) 0);
  250.          s = *xargv;
  251.          while (*s)
  252.          {
  253.             if (!isdigit (*s))
  254.                fatal ("Numeric argument required", (char *) 0, (char *) 0);
  255.             s++;
  256.          }
  257.          if (c == 'b')
  258.          {
  259.             check = atoi (*xargv);
  260.             if ((check < 1 || check > 3) && check != 5)
  261.                fatal ("Invalid block check", (char *) 0, (char *) 0);
  262.          }
  263. #ifdef DEBUG
  264.          else if (c == 'E')
  265.          {
  266.             errorrate = atoi (*xargv);
  267.             if (errorrate > 100)
  268.                fatal ("Invalid error rate", (char *) 0, (char *) 0);
  269.          }
  270. #endif /* DEBUG */
  271.          else if (c == 'w')
  272.          {
  273.             // maximum number of window slots to negotiate
  274.             k.wslots_max = atoi (*xargv);
  275.             if (k.wslots_max == 0)
  276.                k.wslots_max = 1;
  277.             if (k.wslots_max < 1 || k.wslots_max > P_WSLOTS)
  278.                fatal ("Invalid no. of window slots", (char *) 0, (char *) 0);
  279.          }
  280.          else if (c == 'l')
  281.          {
  282.             int maxlen;
  283.             // maximum packet lengths
  284.             maxlen = atoi (*xargv);
  285.             if (maxlen < 10 || maxlen > P_PKTLEN)
  286.                fatal ("Invalid packet maxlen", (char *) 0, (char *) 0);
  287.             k.p_maxlen = maxlen;
  288.          }
  289.          break;
  290.  
  291.       case 'h':                /* Help */
  292.       case '?':
  293.          usage ();
  294.  
  295.       case 'B':                /* Force binary file transfer */
  296.          xmode = 1;             /* So no automatic switching */
  297.          ftype = BINARY;
  298.          break;
  299.  
  300.       case 'T':                /* Force text file transfer */
  301.          xmode = 1;             /* So no automatic switching */
  302.          ftype = TEXT;
  303.          break;
  304.  
  305.       case 'R':                /* Tell Kermit it's in remote mode */
  306.          remote = 1;
  307.          break;
  308.  
  309.       case 'L':                /* Tell Kermit it's in local mode */
  310.          remote = 0;
  311.          break;
  312.  
  313.       case 'k':                /* Keep incompletely received files */
  314.          keep = 1;
  315.          break;
  316.  
  317.       case 'S':                /* Synchronize a server by sending E-packet */
  318.          sync_server = 1;
  319.          break;
  320.  
  321.       case 'p':                /* Parity */
  322.          if (*(xp + 1))
  323.             fatal ("Invalid argument bundling", (char *) 0, (char *) 0);
  324.          xargv++, xargc--;
  325.          if ((xargc < 1) || (**xargv == '-'))
  326.             fatal ("Missing parity", (char *) 0, (char *) 0);
  327.          switch (x = **xargv)
  328.          {
  329.          case 'e':             /* Even */
  330.          case 'o':             /* Odd */
  331.          case 'm':             /* Mark */
  332.          case 's':
  333.             parity = x;
  334.             break;              /* Space */
  335.          case 'n':
  336.             parity = 0;
  337.             break;              /* None */
  338.          default:
  339.             fatal ("Invalid parity '", *xargv, "'");
  340.          }
  341.          break;
  342.  
  343. #ifdef DEBUG
  344.       case 'd':
  345.          dbg++;
  346.          break;
  347. #else
  348.       case 'd':
  349.          fprintf (stderr, "ignoring -d flag -- debugging code not present\n");
  350.          break;
  351. #endif /* DEBUG */
  352.  
  353.       default:                 /* Anything else */
  354.          fatal ("Unknown command-line option ", *xargv,
  355.                 " type 'eksw -h' for help.");
  356.       }
  357.       c = *++xp;                /* See if options are bundled */
  358.    }
  359.    return (action);
  360. }
  361.  
  362. int
  363. main (int argc, char **argv)
  364. {
  365.    int loop;
  366.  
  367.    int status, rx_len = 0, xact;
  368.    char c;
  369.    UCHAR *inbuf;
  370.    char ttyname[100];
  371.    long baud;
  372.  
  373. #if 0
  374.    fprintf (stderr, "MAIN Options:\n");
  375.    fprintf (stderr, " IBUFLEN=%d\n", IBUFLEN);
  376.    fprintf (stderr, " OBUFLEN=%d\n", OBUFLEN);
  377.    fprintf (stderr, " IDATALEN=%d\n", IDATALEN);
  378.    fprintf (stderr, " P_PKTLEN=%d\n", P_PKTLEN);
  379.    fprintf (stderr, " P_WSLOTS=%d\n", P_WSLOTS);
  380. //      fprintf (stderr, " F_SW\n");
  381. //      fprintf (stderr, " F_SSW\n");
  382. //      fprintf (stderr, " F_TSW\n");
  383. #endif
  384.  
  385.    k.wslots_max = 1;            // default to use one window slot
  386.    k.p_maxlen = P_PKTLEN;
  387.  
  388.    parity = P_PARITY;           /* Set this to desired parity */
  389.    status = X_OK;               /* Initial kermit status */
  390.  
  391.    if (argc == 1)
  392.    {
  393.       fprintf (stderr, "usage: eksw [tty baud] [options]\n");
  394.       exit (1);
  395.    }
  396.  
  397.    if (argv[1][0] == '-')
  398.    {
  399.       strncpy (ttyname, "stdin", sizeof (ttyname) - 1);
  400.       baud = 0;
  401.  
  402.       xargc = argc;
  403.       xargv = argv;
  404.    }
  405.    else
  406.    {
  407.       strncpy (ttyname, argv[1], sizeof (ttyname) - 1);
  408.       baud = atol (argv[2]);
  409.  
  410.       xargc = argc - 2;
  411.       xargv = argv + 2;
  412.    }
  413.  
  414.    xname = argv[0];
  415.  
  416.    while (--xargc > 0)
  417.    {                            /* Loop through command-line words */
  418.       xargv++;
  419.       if (**xargv == '-')
  420.       {                         /* Have dash */
  421.          c = *(*xargv + 1);     /* Get the option letter */
  422.          xact = doarg (c);      /* Go handle the option */
  423.          if (xact < 0)
  424.             doexit (FAILURE);
  425.       }
  426.       else
  427.       {                         /* No dash where expected */
  428.          fatal ("Malformed command-line option: '", *xargv, "'");
  429.       }
  430.    }
  431.    if (!action)                 /* Nothing to do, give usage message */
  432.       usage ();
  433.  
  434. //      fprintf(stderr,"dbg=%d\n",dbg);
  435.  
  436.    /*
  437.     * THE REAL STUFF IS FROM HERE DOWN 
  438.     */
  439.  
  440.    if (!devopen (ttyname, baud))        /* Open the communication device */
  441.       doexit (FAILURE);
  442.    if (!devsettings ("dummy"))  /* Perform any needed settings */
  443.       doexit (FAILURE);
  444.    if (dbg == 1)
  445.    {                            /* Open debug log if requested */
  446. //              fprintf(stderr,"opening debug.log without time stamps\n");
  447.       debug (DB_OPN, "debug.log", 0, 0);
  448.    }
  449.    if (dbg == 2)
  450.    {                            /* Open debug log with time stamps */
  451. //              fprintf(stderr,"opening debug.log with time stamps\n");
  452.       debug (DB_OPNT, "debug.log", 0, 0);
  453.    }
  454.  
  455.    debug (DB_MSG, "MAIN Initializing...", 0, 0);
  456.  
  457. #ifdef DEBUG
  458.    debug (DB_LOG, "MAIN SIMULATED ERROR RATE", 0, errorrate);
  459.    if (errorrate)
  460.       srand (seed);             /* Init random error generator */
  461. #endif /* DEBUG */
  462.  
  463.    /*
  464.     * Fill in parameters for this run 
  465.     */
  466.  
  467.    k.send_pause_us = 1000000;
  468.    k.send_pause_us = 0;
  469.    k.baud = baud;
  470.  
  471.    k.xfermode = xmode;          /* Text/binary automatic/manual */
  472.    k.remote = remote;           /* Remote vs local */
  473.    k.binary = ftype;            /* 0 = text, 1 = binary */
  474.    k.parity = parity;           /* Communications parity */
  475.    if (check == 5)
  476.    {
  477.       k.bct = 3;                /* Block check type 3 for all packets */
  478.       k.bcta3 = 1;
  479.    }
  480.    else
  481.    {
  482.       k.bct = check;            /* Block check type */
  483.       k.bcta3 = 0;
  484.    }
  485.    k.ikeep = keep;              /* Keep incompletely received files */
  486.    k.filelist = cmlist;         /* List of files to send (if any) */
  487.    k.cancel = 0;                /* Not canceled yet */
  488.  
  489.    /*
  490.     * Fill in the i/o pointers 
  491.     */
  492.  
  493.    k.zinbuf = i_buf;            /* File input buffer */
  494.    k.zinlen = IBUFLEN;          /* File input buffer length */
  495.    k.zincnt = 0;                /* File input buffer position */
  496.    k.obuf = o_buf;              /* File output buffer */
  497.    k.obuflen = OBUFLEN;         /* File output buffer length */
  498.    k.obufpos = 0;               /* File output buffer position */
  499.  
  500.    /*
  501.     * Fill in function pointers 
  502.     */
  503.  
  504.    k.rxd = readpkt;             /* for reading packets */
  505.    k.txd = tx_data;             /* for sending packets */
  506.    k.ixd = inchk;               /* for checking connection */
  507.    k.openf = openfile;          /* for opening files */
  508.    k.finfo = fileinfo;          /* for getting file info */
  509.    k.readf = readfile;          /* for reading files */
  510.    k.writef = writefile;        /* for writing to output file */
  511.    k.closef = closefile;        /* for closing files */
  512. #ifdef DEBUG
  513.    k.dbf = dbg ? dodebug : 0;   /* for debugging */
  514. #else
  515.    k.dbf = 0;
  516. #endif /* DEBUG */
  517.  
  518.    /*
  519.     * Initialize Kermit protocol 
  520.     */
  521.  
  522.    debug (DB_LOG, "MAIN action", 0, action);
  523.  
  524.    status = kermit (K_INIT, &k, 0, "eksw init", &r);
  525.    debug (DB_LOG, "MAIN K_INIT kermit return status", 0, status);
  526.    if (status == X_ERROR)
  527.       doexit (FAILURE);
  528.  
  529.    if (sync_server)
  530.    {
  531.       // Send an E-pkt before starting protocol to reset a kermit server
  532.       // The E-pkt will force an exit for simple send or receive kermits
  533.       if (kermit (K_SYNC, &k, 0, "eksw sync", &r) == X_ERROR)
  534.          doexit (FAILURE);
  535.    }
  536.  
  537.    if (action == A_SEND)
  538.       status = kermit (K_SEND, &k, 0, "eksw send", &r);
  539.    if (action == A_GET)
  540.       status = kermit (K_GET, &k, 0, "eksw get", &r);
  541.    /*
  542.     * Now we read a packet ourselves and call Kermit with it.  Normally,
  543.     * Kermit would read its own packets, but in the embedded context, the 
  544.     * device must be free to do other things while waiting for a packet
  545.     * to arrive.  So the real control program might dispatch to other
  546.     * types of tasks, of which Kermit is only one.  But in order to read
  547.     * a packet into Kermit's internal buffer, we have to ask for a buffer 
  548.     * address and slot number.
  549.     * 
  550.     * To interrupt a transfer in progress, set k.cancel to I_FILE to
  551.     * interrupt only the current file, or to I_GROUP to cancel the
  552.     * current file and all remaining files.  To cancel the whole
  553.     * status, call Kermit with K_ERROR. 
  554.     */
  555.    loop = 0;
  556.    while (status != X_DONE)
  557.    {
  558.       loop++;
  559.       /*
  560.        * Here we block waiting for a packet to come in (unless readpkt
  561.        * times out). Another possibility would be to call inchk() to see 
  562.        * if any bytes are waiting to be read, and if not, go do
  563.        * something else for a while, then come back here and check
  564.        * again. 
  565.        */
  566.  
  567.       debug (DB_LOG, "MAIN -------------- loop", 0, loop);
  568.  
  569.       if (ok2rxd (&k))
  570.       {
  571.          inbuf = k.ipktbuf;
  572.  
  573.          rx_len = k.rxd (&k, inbuf, P_PKTLEN);  /* Try to read a packet */
  574.  
  575.          debug (DB_LOG, "MAIN rx_len", 0, rx_len);
  576.          debug (DB_HEX, "MHEX", inbuf, rx_len);
  577.  
  578.          if (rx_len < 1)
  579.          {                      /* No data was read */
  580.             if (rx_len < 0)     /* If there was a fatal error */
  581.                doexit (FAILURE);        /* give up */
  582.  
  583.             /*
  584.              * This would be another place to dispatch to another task 
  585.              * while waiting for a Kermit packet to show up. 
  586.              */
  587.  
  588.          }
  589.       }
  590.  
  591.       /*
  592.        * Handle the input 
  593.        *
  594.        * For simplicity, kermit() ACKs the packet immediately after
  595.        * verifying it was received correctly.  If, afterwards, the
  596.        * control program fails to handle the data correctly (e.g. can't
  597.        * open file, can't write data, can't close file), then it tells
  598.        * Kermit to send an Error packet next time through the loop. 
  599.        */
  600.  
  601.       status = kermit (K_RUN, &k, rx_len, "", &r);
  602.       debug (DB_LOG, "MAIN K_RUN return status", 0, status);
  603.  
  604.       switch (status)
  605.       {
  606.       case X_OK:
  607.          /*
  608.           * This shows how, after each packet, you get the protocol
  609.           * state, file name, date, size, and bytes transferred so far. 
  610.           * These can be used in a file-transfer progress display, log, 
  611.           * etc. 
  612.           */
  613. #if 0
  614.          debug (DB_LOG, "NAME",
  615.                 r.filename ? (uchar *) r.filename : (uchar *) "(NULL)", 0);
  616.          debug (DB_LOG, "DATE",
  617.                 r.filedate ? (uchar *) r.filedate : (uchar *) "(NULL)", 0);
  618.          debug (DB_LOG, "SIZE", 0, r.filesize);
  619.          debug (DB_LOG, "STATE", 0, r.status);
  620.          debug (DB_LOG, "SOFAR", 0, r.sofar);
  621. #endif
  622.          /*
  623.           * Maybe do other brief tasks here... 
  624.           */
  625.          continue;              /* Keep looping */
  626.       case X_DONE:
  627.          debug (DB_MSG, "MAIN X_DONE", 0, 0);
  628.          break;                 /* Finished */
  629.       case X_ERROR:
  630.          debug (DB_MSG, "MAIN error", 0, 0);
  631.          doexit (FAILURE);      /* Failed */
  632.          break;
  633.       default:
  634.          debug (DB_LOG, "MAIN unknown status=%d", 0, status);
  635.          break;
  636.       }
  637.    }
  638.    doexit (SUCCESS);
  639.    return (0);
  640. }
  641.