
/****************************************************************************/
/*                                                                          */
/*      NNstat -- Internet Statistics Collection Package                    */
/*                                                                          */
/*            Written by: Bob Braden & Annette DeSchon                      */
/*            USC Information Sciences Institute                            */
/*            Marina del Rey, California                                    */
/*                                                                          */
/*      Copyright (c) 1991 University of Southern California.               */
/*      All rights reserved.                                                */
/*                                                                          */
/*      Redistribution and use in source and binary forms are permitted     */
/*      provided that the above copyright notice and this paragraph are     */
/*      duplicated in all such forms and that any documentation,            */
/*      advertising materials, and other materials related to such          */
/*      distribution and use acknowledge that the software was              */
/*      developed by the University of Southern California, Information     */
/*      Sciences Institute.  The name of the University may not be used     */
/*      to endorse or promote products derived from this software           */
/*      without specific prior written permission.                          */
/*      THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR        */
/*      IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
/*      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR          */
/*      PURPOSE.                                                            */
/*                                                                          */
/****************************************************************************/

static char rcsid[]=
  "$Header: /tmp_mnt/r/jove_staff3/mogul/alpha/code/NNstat/RCS/logfile.c,v 1.3 1993/08/31 23:47:46 mogul Exp $";

/*
 *         logfile.c -- Functional Routines for collect.
 */
 
/*
 *  CHANGES:
 *    13Oct89 Merit: Set mode of new files
 *      Rel 3.0:
 *    RTB: Simplify code a little.
 *    RTB: Fix bug that caused some checkpoints to be lost.
 *    Aug93/DECWRL: Alpha/OSF port.
 */

#include <stdio.h>
#include <rpc/rpc.h>
#include <errno.h>
#include <ctype.h>
#include <strings.h>

#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/file.h>
#include <netdb.h>

#include "collect.h"

extern FILE *tracefp;
extern boolean needlog;
extern int chkpnt, interval, clear;  /* times in seconds */
extern XDR R_XDR;
extern time_t CurrTime;
int openmode = -1;

struct obj_desc *o_ptr; /* ptr to current log info */
FILE *logfp;

/*
 *   Create a new log file
 *
 */
void
create_log(host, objptr, start)
   char *host;
   struct obj_desc *objptr;
   time_t start;  /* startup time, for generating file name */
{
   struct tm *t;
   char *cp, tempstr[200];

   t = localtime(&start);
   
   strncpy(tempstr,host,15);
   if (isalpha(host[0]) && (strlen(host) > 6)) {
      if ((cp = index(tempstr, '.')) != NULL)
         *cp = '\0';
      }
   strcat(tempstr,"-");
   strcat(tempstr,objptr->sname);
   
   sprintf(objptr->fname,"%s.%2.2d%2.2d.%2.2d%2.2d",
           tempstr, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min);
   printf("Creating log file: %s\n",objptr->fname);
   
   if ((objptr->logptr = fopen(objptr->fname,"w")) != NULL) {
      if (openmode != -1) fchmod(fileno(objptr->logptr), openmode);
      strcpy(tempstr, ctime(&start));
      tempstr[strlen(tempstr)-1] = 0;
      fprintf(objptr->logptr, "\nLog created on %s, for host %s.\n",
                tempstr, host);
      if (interval || chkpnt)
         fprintf(objptr->logptr, 
       "    Sample interval = %d minutes; checkpoint interval = %d minutes.\n",
                  interval/60, chkpnt/60);
      if (clear)
         fprintf(objptr->logptr, "    Clear interval = %d minutes.\n", clear/60);
      fprintf(objptr->logptr, "    Object name = '%s'.\n", 
                    objptr->sname);
      objptr->saventry = TRUE;
      objptr->logindex = ftell(objptr->logptr);
      }
} /* create_log */


/*
 *  Find per-object slot with object name matching *object, 
 *  in per-host entry pointed to by c_ptr.  Open log file and save FILE
 *  ptr in logptr field.  If no matching slot, find empty slot, fill in
 *  object name, create (and open) corresponding log file, and set
 *  saventry switch to TRUE.
 */
struct obj_desc *
find_object(c_ptr, object)
   struct collector *c_ptr;
   char *object;
{
   struct obj_desc *objptr;
   int i;

   for (i=0; i < MAX_STATS; i++)  {
       objptr = &c_ptr->s[i];
       if (strlen(c_ptr->s[i].sname) == 0) {  /* Empty slot */
          strcpy(objptr->sname, object);
          break;  /* go create log file */
       }
       else if (strcmp(c_ptr->s[i].sname, object) == 0) { /* Name matches */
          if (strlen(c_ptr->s[i].fname)) {
             if (objptr->logptr = fopen(objptr->fname, "r+"))
                 return(objptr);  /* success */
          }
          break;  /* go create log file */
       }
   }
   
   create_log(c_ptr->hostname, objptr, c_ptr->creation);
   return(objptr);
} /* find_object */


/*
 *  int Start_Read(c_ptr, rspP)
 *
 *   This routine is called by Get_reply() for reading an object remotely.
 *   When it is called, the standard object state has already been read into
 *   OBJ struct *rspP.  c_ptr points to host control element (struct collector).
 *
 *   This routine finds/creates/positions a log file (if necessary) to
 *   record the data.  Specifically, its primary side-effect is to set globals:
 *       logfp, the file descriptor for writing a log file, and
 *       o_ptr, a ptr to the object slot in the host control element,
 *                   for reading this object.
 *
 *   Returns TRUE if OK, FALSE if it fails.
 */
boolean
Start_Read(c_ptr, rspP)
   struct collector *c_ptr;  /* per-host structure */
   OBJ *rspP;
{
   struct tm *tp;
        
   if (! needlog) {  /* log to stdout */
      logfp = stdout;
      return(TRUE);
   }

   if ((o_ptr = find_object(c_ptr, rspP->obj_name)) != NULL &&
                      o_ptr->logptr != NULL)
      logfp = o_ptr->logptr;
   else
      return(FALSE);
            
   if (o_ptr->saventry) {
           /* First time for this log file (saventry switch is set TRUE by
            *    find_object() when it creates new log file);
            * initialize checkpoint and reset times.
            * 
            *   Checkpoint time: ctime = creation - (creation mod 60 min)
            */
      tp = localtime(&c_ptr->creation);
      o_ptr->ctime = c_ptr->creation - ((tp->tm_min*60) + tp->tm_sec);
      if (chkpnt)
         while (CurrTime >= (o_ptr->ctime + chkpnt))
            o_ptr->ctime += chkpnt;
      o_ptr->rtime = rspP->obj_state.cleartime;
   }
   else {
      if (o_ptr->rtime != rspP->obj_state.cleartime) {
            /*  Object has been cleared.  Must not overwrite previous entry,
             *    i.e., force checkpoint now.
             */
         fseek(logfp, -1, 2);     /* start at end of log file, before EOF */
         o_ptr->rtime = rspP->obj_state.cleartime;
         /*** fprintf(logfp, "\n"); ***/
         o_ptr->logindex = ftell(logfp);
         if (tracefp) {
             fprintf(tracefp, "Checkpoint previous.\n");
             fflush(tracefp);
         }
      }
      else
         fseek(logfp,o_ptr->logindex,0); /* start at last start point */
      if (chkpnt && 
              (CurrTime >= (o_ptr->ctime + chkpnt))) {
              /*  It is checkpoint time.  Set switch (saventry = TRUE) to
               *   advance logindex to EOF in End_Read(), and compute next
               *   checkpoint time.
               */
         o_ptr->saventry = TRUE;
         while (CurrTime >= (o_ptr->ctime + chkpnt))
            o_ptr->ctime += chkpnt;
      }
   }
   return(TRUE);
} /* Start_Read() */


void
End_Read()
{
    if (needlog) {
         if (o_ptr->saventry) {
            fprintf(logfp, "\n");
            o_ptr->logindex = ftell(logfp);
            if (tracefp) {
                fprintf(tracefp, "Checkpoint.\n");
                fflush(tracefp);
            }
         }
         o_ptr->saventry = FALSE;
         fprintf(logfp,"%c", EOF);
         fflush(logfp);
         fclose(logfp);
         logfp = NULL;
    }
} /* End_Read */
