/* -*- c -*-
 *
 * Author:      James Brister <brister@vix.com> -- berkeley-unix --
 * Start Date:  Mon, 15 Jan 1996 17:31:58 +1100
 * Project:     INN -- innfeed
 * File:        main.c
 * RCSId:       $Id: main.c,v 1.16 1996/08/20 13:28:09 brister Exp $
 *
 * Copyright:   Copyright (c) 1996 by Internet Software Consortium
 *
 *              Permission to use, copy, modify, and distribute this
 *              software for any purpose with or without fee is hereby
 *              granted, provided that the above copyright notice and this
 *              permission notice appear in all copies.
 *
 *              THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE
 *              CONSORTIUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 *              SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *              MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET
 *              SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
 *              INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *              WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 *              WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 *              TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
 *              USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Description: Main routines for the innfeed program.
 * 
 */

#if ! defined (lint)
static const char *rcsid = "$Id: main.c,v 1.16 1996/08/20 13:28:09 brister Exp $" ;
static void use_rcsid (const char *rid) {   /* Never called */
  use_rcsid (rcsid) ; use_rcsid (rid) ;
}
#endif


#include "config.h"             /* system specific configuration */

#include <stdlib.h>
#include <syslog.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include <math.h>

#if defined (DO_HAVE_UNISTD)
#include <unistd.h>
#endif

#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "misc.h"
#include "tape.h"
#include "article.h"
#include "msgs.h"
#include "buffer.h"
#include "connection.h"


#if defined(DO_HAVE_UNIX_DOMAIN)
#include <sys/un.h>
#endif  /* defined(DO_HAVE_UNIX_DOMAIN) */


#include "endpoint.h"
#include "host.h"
#include "innlistener.h"


extern int debugWrites ;
int sigFlag ;

static bool getHostInfo (FILE *fp,
                         char **name,
                         char **ipname,
                         u_int *articleTimeout,
                         u_int *responseTimeout,
                         u_int *initialConnections,
                         u_int *maxConnections,
                         u_int *maxChecks,
                         bool *streaming,
                         double *lowFilter,
                         double *highFilter,
                         u_short *portNumber) ;
static bool getOptUInt (u_int *field, char *line, u_int fNum, u_int defVal) ;
static bool getOptBool (bool *field, char *line, u_int fNum, bool defVal) ;
static bool getOptDouble (double *field, char *line, u_int fieldNum,
                          double defVal) ;
static void sigchld (int sig) ;
static void sigusr (int sig) ;
static void usage (int) ;
static void gprintinfo (void) ;


u_int defaultArticleTimeout ;
u_int defaultResponseTimeout ;
u_int defaultInitialConnections ;
u_int defaultMaxConnections ;
u_int defaultMaxChecks ;
bool defaultStreaming ;
double defaultLowFilter ;
double defaultHighFilter ;
u_short defaultPortNumber ;
bool talkToSelf ;

extern char *versionInfo ;

#if defined (sun)
extern char *optarg ;           /* needed for Solaris */
#endif

int main (int argc, char **argv)
{
  EndPoint ep ;
  InnListener listener ;
  Host nHost ;
  int optVal ;
  const char *configFile = CONFIG_FILE ;
  const char *subProgram = NULL ;
  char *logFile = NULL ;
  FILE *fp ;
  char *name, *ipName ;
  u_int artTout, respTout, initCxns, maxCxns, maxChecks ;
  double lowFilter, highFilter ;
  bool streaming ;
  bool seenV = false ;
  u_short portNum ;
  bool dynamicPeers = false ;
  time_t now = theTime() ;
  char dateString [30] ;

  strcpy (dateString,ctime(&now)) ;
  dateString [24] = '\0' ;

  if ((program = strrchr (argv [0],'/')) == NULL)
    program = argv [0] ;
  else
    program++ ;

  gPrintInfo = gprintinfo ;


#define OPT_STRING "zymvhxb:l:c:d:s:"
  
  while ((optVal = getopt (argc,argv,OPT_STRING)) != EOF)
    {
      switch (optVal) 
        {
          case 'd':
            loggingLevel = atoi (optarg) ;
            break ;

          case 'z':
            hostLogConnectionStats (true) ;
            break ;
            
          case 'x':
            talkToSelf = true ;
            break ;
            
          case 's':
            subProgram = optarg ;
            break ;

          case 'b':
            setTapeDirectory (optarg) ;
            break ;

          case 'l':
            logFile = optarg ;
            break ;

          case 'm':
            artLogMissingArticles (true) ;
            break ;

          case 'c':
            configFile = optarg ;
            break ;

          case 'h':
            usage (0) ;

          case 'v':
            seenV = true ;
            break ;

          case 'y':
            dynamicPeers = true ;
            break ;
	
          default:
             	usage (1) ;	
        }
    }

  if (loggingLevel == 0 && fileExistsP (DEBUG_FILE))
    loggingLevel = 1 ;

    /* XXX this need to be an option */
  artBitFiddleContents (true) ; 
  
  if (logFile != NULL)
    {
      FILE *fpr ;

      if (((fpr = freopen (logFile,"a",stdout)) == NULL) || (fpr != stdout))
        die ("fopen (%s): %s",logFile,strerror (errno)) ;

      if (((fpr = freopen (logFile, "a", stderr)) == NULL) || (fpr != stderr))
        die ("fopen (%s): %s", logFile, strerror (errno)) ;
    }
  else if (!isatty (2))
    {
        /* redirect stderr and stdout if they're going to /dev/null */
      FILE *fpr ;
      
      fprintf (stderr,"Redirecting stdout and stderr to %s\n", LOG_FILE) ;
      
      fpr = freopen (LOG_FILE,"a",stdout) ;
      if (fpr != stdout)
        die ("fopen (%s): %s", LOG_FILE, strerror (errno)) ;
      
      fpr = freopen (LOG_FILE, "a", stderr) ;
      if (fpr != stderr)
        die ("fopen (%s): %s", LOG_FILE, strerror (errno)) ;
    }

#if defined (DO_HAVE_SETBUFFER)
  setbuffer (stdout, NULL, 0) ;
  setbuffer (stderr, NULL, 0) ;
#else
  setbuf (stdout, NULL) ;
  setbuf (stderr, NULL) ;
#endif

  if (seenV)
    {
      warn ("%s version: %s\n",program, versionInfo) ;
      exit (0) ;
    }

  openlog (program,L_OPENLOG_FLAGS | LOG_PID,LOG_NEWS) ;
  syslog (LOG_NOTICE,STARTING_PROGRAM,versionInfo,dateString) ;

  openfds = 4 ;                 /* stdin, stdout, stderr and syslog */
  
  if ( strlen (configFile) == 0 || !fileExistsP (configFile) )
    {
      syslog (LOG_ERR, NOSUCH_CONFIG, configFile) ;
      dprintf (1,"No such config file: %s\n", configFile) ;
      exit (1) ;
    }

  if ( !isDirectory (getTapeDirectory()) )
    {
      syslog (LOG_ERR,NOT_A_DIR,getTapeDirectory()) ;
      dprintf (1,"Not a directory : %s\n",getTapeDirectory()) ;
      exit (1) ;
    }
  
  if (subProgram != NULL && talkToSelf == true)
    {
      syslog (LOG_ERR,NO_X_AND_S) ;
      dprintf (1,"Cannot specify '-x' and '-s' together\n") ;
      exit (1) ;
    }
  else if (subProgram != NULL)
    {
      int fds [2] ;
      int pid ;

      if (pipe (fds) < 0)
        {
          syslog (LOG_CRIT,PIPE_FAILURE) ;
          exit (1) ;
        }

      if ((pid = fork ()) < 0)
        {
          syslog (LOG_CRIT,FORK_FAILURE) ;
          exit (1) ;
        }
      else if (pid == 0)
        {                       /* child */
          close (fds[0]) ;
          close (0) ;
          close (1) ;
          close (2) ;
          dup2 (fds[1],1) ;
          dup2 (fds[1],2) ;
          execlp ("sh","sh", "-c", subProgram, NULL) ;
          perror ("execlp") ;
          exit (1) ;
        }
      else
        {                       /* parent */
          close (0) ;
          dup2 (fds[0],0) ;
          close (fds[1]) ;
          signal(SIGCHLD,sigchld) ;
          openfds++ ;
        }
    }
  else  if (talkToSelf)
    {
        /* We're not really getting information from innd or a subprogram,
           but are just processing backlog files. We set up a pipe to ourself
           that we never write to, to simulate an idle innd. */
      int pipefds [2] ;

      if (pipe (pipefds) != 0)
        {
          syslog (LOG_ERR,PIPE_FAILURE) ;
          exit (1) ;
        }

      close (0) ;
      dup2 (pipefds [0], 0) ;

      openfds++ ;
      openfds++ ;
    }
  else 
    {
      struct stat buf ;

      if (fstat (0,&buf) < 0)
        {
          syslog (LOG_ERR,FSTAT_FAILURE,"stdin") ;
          exit (1) ;
        }
      else if (S_ISREG (buf.st_mode))
        {
          fprintf (stderr,
                   "stdin looks to be a redirected file. Innfeed needs\n") ;
          fprintf (stderr,
                   "stdin to be another program, or put your file in the\n") ;
          fprintf (stderr,"appropriate place and use the '-x' option\n") ;
          exit (0) ;
        }
    }
  
  if (chdir (NEWSSPOOL) != 0)
    {
      syslog (LOG_ERR,CD_FAILED,NEWSSPOOL) ;
      exit (1) ;
    }


    /* hook up the endpoint to the source of new article information (usually
       innd). */
  ep = newEndPoint (0) ;        /* fd 0, i.e. stdin */

    /* now arrange for this endpoint to always be the first one checked for
       possible activity. */
  setMainEndPoint (ep) ;

  tapeSetCheckpointPeriod (TAPE_CHECKPOINT_PERIOD) ;

  listener = newListener (ep, talkToSelf,dynamicPeers) ;
  mainListener = listener ;
  
  if ((fp = fopen (configFile,"r")) == NULL)
    {
      syslog (LOG_ERR,FOPEN_FAILURE, configFile) ;
      exit (0) ;
    }

  openfds++ ;
  
  while (getHostInfo (fp, &name, &ipName, &artTout, &respTout, &initCxns,
                      &maxCxns, &maxChecks, &streaming, &lowFilter,
                      &highFilter,&portNum))
    {
      nHost = newHost (listener,name,ipName,artTout,respTout,initCxns,
                       maxCxns,maxChecks,portNum,CLOSE_PERIOD,
                       streaming,lowFilter,highFilter) ;

      /* this is where we'll die if the locks are still held. */
      if (nHost == 0)
        {
          syslog (LOG_ERR,NO_HOST,name) ;
        }
      else 
        {
          if (initCxns == 0 && talkToSelf)
            syslog (LOG_NOTICE,BATCH_AND_NO_CXNS,name) ;

          dprintf (1,"Adding %s %s article (%d) response (%d) initial (%d) max con (%d) max checks (%d) portnumber (%d) streaming (%s) lowFilter (%.2f) highFilter (%.2f)\n",
                   name, ipName, artTout, respTout, initCxns, maxCxns,
                   maxChecks, portNum, streaming ? "true" : "false",
                   lowFilter, highFilter) ;

          if ( nHost != NULL && !listenerAddPeer (listener,nHost) )
            die ("failed to add a new peer\n") ;
        }
    }
  

  if ( !feof (fp) )
    {
      syslog (LOG_ERR,PARSE_FAILURE) ;
      exit (1) ;
    }

  fclose (fp) ;

  openfds-- ;
  
    /* we can increment and decrement logging levels by sending SIGUSR{1,2} */
  signal (SIGUSR1,sigusr) ;
  signal (SIGUSR2,sigusr) ;

  Run () ;
  
  exit (0) ;
}


static void usage (int val)
{
  fprintf (stderr,"usage: %s [ options ]\n\n",
           program) ;
  fprintf (stderr,"Version: %s\n\n",versionInfo) ;
  fprintf (stderr,"Config file: %s\n",CONFIG_FILE) ;
  fprintf (stderr,"Backlog directory: %s\n",TAPE_DIRECTORY) ;
  fprintf (stderr,"\n\nLegal options are:\n") ;
  fprintf (stderr,"\t-d num      set the logging level to num (an integer).\n");
  fprintf (stderr,"\t            Larger value means more logging. 0 means no\n");
  fprintf (stderr,"\t            logging. The default is 0\n");
  fprintf (stderr,"\t-l file     redirect stderr and stdout to the given file.\n");
  fprintf (stderr,"\t            When run under INN they normally are redirected to\n");
  fprintf (stderr,"\t            /dev/null. This is needed if using '-d'.\n");
  fprintf (stderr,"\t-s command  run the given command in a subprocess and use\n");
  fprintf (stderr,"\t            its output as article information instead of\n");
  fprintf (stderr,"\t            running under innd\n");
  fprintf (stderr,"\t-x          Do not read any articles information off stdin,\n");
  fprintf (stderr,"\t            but simply process backlog files and then exit\n");
  fprintf (stderr,"\t            when done\n");
  fprintf (stderr,"\t-c file     Use the given file as the config file instead of the\n");
  fprintf (stderr,"\t            default of %s\n",CONFIG_FILE);
  fprintf (stderr,"\t-z          have each of the connections issue their own stats\n");
  fprintf (stderr,"\t            whenever they close, or whenever their controller\n");
  fprintf (stderr,"\t            issues its own stats\n");
  fprintf (stderr,"\t-y          Add peers dynamically. If an unrecognized peername\n");
  fprintf (stderr,"\t            is received from innd, then it is presumed to als\n");
  fprintf (stderr,"\t            be the ip name and a new peer binding is set up\n");
  fprintf (stderr,"\t-m          Log information on all missing articles\n");
  fprintf (stderr,"\t-v          print version information\n");
  fprintf (stderr,"\t-h          print this message\n");
  fprintf (stderr,"\t-b dir      Use the given directory as the the storage\n");
  fprintf (stderr,"\t            place for backlog (tape) files and lock files.\n");

  exit (val) ;
}

  /* parse lines of the form used in the config file:

     name:fqdn:article-timeout:initial-connections:response-timeout:
     max-connections:max-q-size:streaming:low-filter:high-filter:portnum

     XXX i'm not handling continuation lines yet.
     */


static bool getHostInfo (FILE *fp,
                         char **name,
                         char **ipName,
                         u_int *articleTimeout,
                         u_int *responseTimeout,
                         u_int *initialConnections,
                         u_int *maxConnections,
                         u_int *maxChecks,
                         bool *streaming,
                         double *lowFilter,
                         double *highFilter,
                         u_short *portNumber) 
{
  static bool seenDefault ;
  char line [1024], copyLine [1024] ;
  char *p, *l ;
  char *field1, *field2 ;
  u_int field3, field4, field5, field6, field7 ;
  bool field8 ;
  double field9, field10 ;
  u_int field11 ;
  bool gotSomething = false ;

  dprintf (1,"Starting...\n") ;
  
  while (fgets (line, sizeof (line), fp) != NULL)
    {
      gotSomething = false ;
      dprintf (1,"Doing config line: %s\n",line) ;
      
      strcpy (copyLine,line) ;  /* copyLine is used for syslog only */
      
      for (l = line ; *l != '\0' && isspace (*l) ; l++)
          /* nada */ ;
      
      if ((p = strchr (l,'#')) == NULL)
        p = l + strlen (l) - 1 ;
      else
        p-- ;

      while (p > l && isspace (*p))
        p-- ;

      *++p = '\0' ;

      if (strlen (l) == 0) 
        continue ;

        /* field 1 the system name */
      if (((field1 = mystrtok (l,":")) == NULL) || (strlen (field1) == 0))
        {
          dprintf (1,"Bad system name in config file line: %s\n", copyLine) ;
          return false ;
        }
      trim_ws (field1) ;

        /* field 2 the fqdn */
      if ((field2 = mystrtok (NULL,":")) == NULL)
        {
          dprintf (1,"Bad system IP name in config file line: %s\n", copyLine) ;
          return false ;
        }
      trim_ws (field2) ;

      if ((strcmp (field1, "default") != 0) && (strlen (field2) == 0))
        {
          dprintf (1,"f2 - 1\n") ;
          return false ;
        }
      else if ((strcmp (field1, "default") == 0) && (strlen (field2) != 0))
        {
          dprintf (1,"f2 - 2\n") ;
          return false ;
        }


        /* field 3 the article timeout */
      if ( !getOptUInt (&field3,copyLine,3,defaultArticleTimeout) )
        return false ;

        /* field 4 the response timeout */
      if ( !getOptUInt (&field4,copyLine,4,defaultResponseTimeout) )
        return false ;

        /* field 5 the number of initial connections to create */
      if ( !getOptUInt (&field5,copyLine,5,defaultInitialConnections) )
        return false ;
      
        /* field 6 the max # of connections */
      if ( !getOptUInt (&field6,copyLine,6,defaultMaxConnections) )
        return false ;

        /* field 7 the max number of checks */
      if ( !getOptUInt (&field7,copyLine,7,defaultMaxChecks) )
        return false ;

      /* field 8 the streaming flag */
      if ( !getOptBool (&field8,copyLine,8,defaultStreaming) )
        return false ;

      /* field 9 the low-pass filter low value. */
      if ( !getOptDouble (&field9,copyLine,9,defaultLowFilter) )
        return false ;

      /* field 10 the low-pass filter high value */
      if ( !getOptDouble (&field10,copyLine,10,defaultHighFilter) )
        return false ;

      /* field 11 the port number */
      if ( !getOptUInt (&field11,copyLine,11,defaultPortNumber) )
        return false ;

      if (field9 > field10)
        {
          syslog (LOG_ERR,LOW_GREATER,field1) ;
          exit (1) ;
        }
      
      if (strcmp (field1,"default") != 0)
        {
          gotSomething = true ;
          break ;
        }

      seenDefault = true ;
      
      defaultArticleTimeout = field3 ;
      defaultResponseTimeout = field4 ;
      defaultInitialConnections = field5 ;
      defaultMaxConnections = field6 ;
      defaultMaxChecks = field7 ;
      defaultStreaming = field8 ;
      defaultLowFilter = field9 ;
      defaultHighFilter = field10 ;
      defaultPortNumber = field11 ;

      dprintf (1,"defaults are set %d %d %d %d %d %s %.2f %.2f %d\n",
               defaultArticleTimeout,
               defaultResponseTimeout,
               defaultInitialConnections,
               defaultMaxConnections,
               defaultMaxChecks,
               defaultStreaming ? "true" : "false",
               defaultLowFilter,
               defaultHighFilter,
               defaultPortNumber
               ) ;
      
    }

  if ( !gotSomething )
    return false ;

  if ( !seenDefault )
    {
      syslog (LOG_ERR,NO_DEFAULT) ;
      return false ;
    }

  *name = strdup (field1) ;
  *ipName = strdup (field2) ;
  *articleTimeout = field3 ;
  *responseTimeout = field4 ;
  *initialConnections = field5 ;
  *maxConnections = field6 ;
  *maxChecks = field7 ;
  *streaming = field8 ;
  *lowFilter = field9 ;
  *highFilter = field10 ;
  *portNumber = field11 ;

  return true ;
}



void getHostDefaults (u_int *articleTout,
                      u_int *respTout,
                      u_int *initialCxns,
                      u_int *maxCxns,
                      u_int *maxChecks,
                      bool *streaming,
                      double *lowFilter,
                      double *highFilter,
                      u_short *portNum)
{
  ASSERT (defaultMaxConnections > 0) ;
  
  ASSERT (articleTout != NULL) ;
  ASSERT (respTout != NULL) ;
  ASSERT (initialCxns != NULL) ;
  ASSERT (maxCxns != NULL) ;
  ASSERT (maxChecks != NULL) ;
  ASSERT (portNum != NULL) ;
  ASSERT (streaming != NULL) ;
  ASSERT (lowFilter != NULL) ;
  ASSERT (highFilter != NULL) ;
  
  
  *articleTout = defaultArticleTimeout ;
  *respTout = defaultResponseTimeout ;
  *initialCxns = defaultInitialConnections ;
  *maxCxns = defaultMaxConnections ;
  *maxChecks = defaultMaxChecks ;
  *streaming = defaultStreaming ;
  *lowFilter = defaultLowFilter ;
  *highFilter = defaultHighFilter ;
  *portNum = defaultPortNumber ;
}


static bool getOptDouble (double *field, char *line, u_int fieldNum,
                          double defVal)
{
  char *tok, *ptr ;

  if ((tok = mystrtok (NULL,":")) == NULL)
    *field = defVal ;
  else if (strlen (tok) > 0)
    {
      errno = 0 ;

      /* yeah, I know I could collapse these all into one giant if. */
      if (((*field = strtod (tok, &ptr)) == 0) && (ptr == tok))
        {
          dprintf (1,"Bad field %d in line: %s\n", fieldNum, line) ;
          return false ;
        }
      else if (*ptr != '\0')
        {
          dprintf (1,"Bad field %d in line: %s\n", fieldNum, line) ;
          return false ;
        }
      else if ((*field == -(HUGE_VAL) || *field == HUGE_VAL) &&
               errno == ERANGE)
        {
          dprintf (1,"Bad field %d in line: %s\n", fieldNum, line) ;
          return false ;
        }
      else if (*field == 0 && errno == ERANGE)
        {
          dprintf (1,"Bad field %d in line: %s\n", fieldNum, line) ;
          return false ;
        }
    }
  else
    *field = defVal ;

  return true ;
}

static bool getOptBool (bool *field, char *line, u_int fieldNum, bool defVal)
{
  char *tok, *ptr, *p ;
  u_int intVal ;

  if ((tok = mystrtok (NULL,":")) == NULL)
    *field = defVal ;
  else if (strlen (tok) > 0)
    {
      intVal = strtol (tok, &ptr, 10) ;
      if (ptr == tok)
        {
          for (p = tok ; *p && isspace (*p) ; p++)
              /* nada */ ;
          if ( *p == 't' || *p == 'T' )
            *field = true ;
          else if ( *p == 'f' || *p == 'F' )
            *field = false ;
          else
            {
              dprintf (1,"Bad field %d in line: %s\n", fieldNum, line) ;
              return false ;
            }
        }
      else if (ptr != '\0')
        {
          dprintf (1,"Bad field %d in line: %s\n", fieldNum, line) ;
          return false ;
        }
      else if (intVal == 0)
        *field = false ;
      else if (intVal == 1)
        *field = true ;
      else
        {
          dprintf (1,"Bad field %d in line: %s\n", fieldNum, line) ;
          return false ;
        }
    }
  else
    *field = defVal ;

  return true ;
}

static bool getOptUInt (u_int *field, char *line, u_int fieldNum, u_int defVal)
{
  char *tok, *ptr ;

  if ((tok = mystrtok (NULL,":")) == NULL)
    *field = defVal ;
  else if (strlen (tok) > 0)
    {
      if (((*field = strtol (tok, &ptr, 10)) == LONG_MAX) || (*ptr != '\0'))
        {
          dprintf (1,"Bad field %d in line: %s\n", fieldNum, line) ;
          return false ;
        }
    }
  else
    *field = defVal ;

  return true ;
}


static void sigchld (int sig)
{
  int pid ;
#if defined (DO_USE_UNION_WAIT)
  union wait status ;
#else
  int status ;
#endif

  (void) sig ;                  /* keep lint happy */
  
#if defined (DO_HAVE_WAITPID)
  pid = waitpid (-1, &status, WNOHANG);
#else
  pid = wait3 (&status, WNOHANG, (struct rusage *) NULL);
#endif

#if 0
  wait (&status) ;              /* we don't care */
#endif

  signal (sig,sigchld) ;
}


  /* SIGUSR1 increments logging level. SIGUSR2 decrements. */
static void sigusr (int sig)
{
  if (sig == SIGUSR1)
    loggingLevel++ ;
  else if (sig == SIGUSR2 && loggingLevel > 0)
    loggingLevel-- ;

  signal (sig,sigusr) ;
}


static void gprintinfo (void)
{
  FILE *fp = fopen (SNAPSHOT_FILE,"a") ;
  time_t now = theTime() ;

  if (fp == NULL)
    {
      syslog (LOG_ERR,NO_SNAPSHOT,SNAPSHOT_FILE) ;
      return ;
    }

#if defined (DO_HAVE_SETBUFFER)
  setbuffer (fp, NULL, 0) ;
#else
  setbuf (fp, NULL) ;
#endif


  fprintf (fp,"----------------------------System snaphot taken at: %s\n",
           ctime (&now)) ;
  gPrintListenerInfo (fp,0) ;
  fprintf (fp,"\n\n\n\n") ;
  gPrintHostInfo (fp,0) ;
  fprintf (fp,"\n\n\n\n") ;
  gPrintCxnInfo (fp,0) ;
  fprintf (fp,"\n\n\n\n") ;
  gPrintArticleInfo (fp,0) ;
  fprintf (fp,"\n\n\n\n") ;
  gPrintBufferInfo (fp,0) ;
  fprintf (fp,"\n\n\n\n") ;
  fclose (fp) ;
}

