#ifndef lint
static char *RCSid = "$Header: /proj/freeware1.0/nfswatch/nfswatch4.1/RCS/logfile.c,v 1.1 1995/08/08 04:40:28 rck Exp $";
#endif

#include "os.h"

/*
 * logfile.c - routines for updating log and snapshot files
 *
 * David A. Curry				Jeffrey C. Mogul
 * Purdue University				Digital Equipment Corporation
 * Engineering Computer Network			Western Research Laboratory
 * 1285 Electrical Engineering Building		250 University Avenue
 * West Lafayette, IN 47907-1285		Palo Alto, CA 94301
 * davy@ecn.purdue.edu				mogul@decwrl.dec.com
 *
 * $Log: logfile.c,v $
 * Revision 1.1  1995/08/08  04:40:28  rck
 * initial checkin
 *
 * Revision 4.2  1993/09/22  14:09:28  davy
 * Added fixes for snapshot code on Solaris 2.x from Gerry Singleton at
 * OpCom.
 *
 * Revision 4.1  1993/09/15  20:52:36  davy
 * Added "-procs" output.  Diffs from Gary Schaps (gls@cirrus.com).
 *
 * Revision 4.0  1993/03/01  19:59:00  davy
 * NFSWATCH Version 4.0.
 *
 * Revision 3.3  1993/01/16  19:08:59  davy
 * Corrected Jeff's address.
 *
 * Revision 3.2  1993/01/15  19:33:39  davy
 * Miscellaneous cleanups.
 *
 * Revision 3.1  1993/01/13  20:18:17  davy
 * Put in OS-specific define scheme, and merged in Tim Hudson's code for
 * SGI systems (as yet untested).
 *
 * Revision 3.0  1991/01/23  08:23:05  davy
 * NFSWATCH Version 3.0.
 *
 * Revision 1.2  90/08/17  15:47:22  davy
 * NFSWATCH Version 2.0.
 * 
 * Revision 1.1  88/11/29  11:20:34  davy
 * NFSWATCH Release 1.0
 * 
 */
#include <sys/param.h>
#include <sys/time.h>
#include <curses.h>
#include <stdio.h>

#include "nfswatch.h"
#include "externs.h"
#include "screen.h"

#ifdef SUNOS5
static char *scrncpy();
#endif

/*
 * snapshot - take a snapshot of the screen.
 */
void
snapshot()
{
	FILE *fp;
	register int x, y;
	char buffer[BUFSIZ];

	/*
	 * We want to append to the snapshot file.
	 */
	if ((fp = fopen(snapshotfile, "a")) == NULL) {
		(void) mvprintw(SCR_PROMPT_Y, SCR_PROMPT_X,
			"could not open \"%s\"", snapshotfile);
		(void) refresh();
		return;
	}

	/*
	 * For all lines but the last one ...
	 */
	for (y = 0; y < LINES - 1; y++) {
		(void) mvprintw(SCR_PROMPT_Y, SCR_PROMPT_X,
			"dumping line %d", y + 1);
		(void) clrtoeol();
		(void) refresh();

		/*
		 * Search backwards on each line for a non-space.
		 * x is the count of significant characters.
		 */
		for (x = COLS - 1; x > 0; x--) {
			/*
			 *  Non-space found, increment Z and exit loop
			 */
			if (curscr->_y[y][x] != ' ') {
				x++;
				break;
			}
		}

		/*
		 * Copy x characters and append a \n and \0 to the
		 * string, then output it.
		 */
#ifdef SUNOS5
		(void) scrncpy(buffer, curscr->_y[y], x);
#else
		(void) strncpy(buffer, curscr->_y[y], x);
#endif
		buffer[x++] = '\n';
		buffer[x] = '\0';

		(void) fputs(buffer, fp);
	}


	(void) fputc('\014', fp);
	(void) fclose(fp);

	/*
	 * Tell them we're done.
	 */
	(void) mvprintw(SCR_PROMPT_Y, SCR_PROMPT_X,
		"screen dumped to \"%s\"", snapshotfile );
	(void) refresh();
}

/*
 * Names of NFS procedures (MUST be kept in the right order)
 *      two leading spaces make things look nicer
 */
char     *local_procs[] = {
	   "  CREATE",     "  GETATTR",    "  GETROOT",    "  LINK",
	   "  LOOKUP",     "  MKDIR",      "  NULLPROC",   "  READ",
	   "  READDIR",    "  READLINK",   "  REMOVE",     "  RENAME",
	   "  RMDIR",      "  SETATTR",    "  STATFS",     "  SYMLINK",
	   "  WCACHE",     "  WRITE",      0
};

/*
 * update_logfile - put out the information to the log file.
 */
void
update_logfile()
{
	char *tstr;
	char *ctime();
	float percent;
	char buf[BUFSIZ];
	struct timeval tv;
	register int i, j, nfstotal;

	long count, tot_count;
	double dcount, sumsqr, sum;
        static char nfsprocs_header[80] = 
            " Procedure          int   pct    total  completed  ave.resp  var.resp  max.resp"; 

	(void) gettimeofday(&tv, (struct timezone *) 0);

	/*
	 * Start a log entry.
	 */
	(void) fprintf(logfp, "#\n# begin\n#\n");
	(void) fprintf(logfp, "Date: %.24s\n", ctime(&tv.tv_sec));

	tv.tv_sec -= starttime.tv_sec;
	tstr = prtime(tv.tv_sec);

	(void) fprintf(logfp, "Cycle Time: %d\n", cycletime);
	(void) fprintf(logfp, "Elapsed Time: %.8s\n", tstr+11);

	/*
	 * Print total packet counters.
	 */
	(void) fprintf(logfp, "#\n# total packets     %8s %8s %8s\n#\n",
		"network", "to host", "dropped");
	(void) fprintf(logfp, "Interval Packets:   %8d %8d %8d\n",
		int_pkt_total, int_dst_pkt_total, int_pkt_drops);
	(void) fprintf(logfp, "Total Packets:      %8d %8d %8d\n",
		pkt_total, dst_pkt_total, pkt_drops);

	/*
	 * Put out a header for the packet counters.
	 */
	(void) fprintf(logfp, "#\n# packet counters         %8s %8s %8s\n#\n",
		"int", "pct", "total");

	/*
	 * Print the packet counters.  Percentage is calculated as
	 * this interval counter over total packets this interval.
	 */
	for (i = 0; i < PKT_NCOUNTERS; i++) {
		if (int_dst_pkt_total) {
			percent = ((float) pkt_counters[i].pc_interval /
				  (float) int_dst_pkt_total) * 100.0;
		}
		else {
			percent = 0.0;
		}

		(void) sprintf(buf, "%s:", pkt_counters[i].pc_name);
		(void) fprintf(logfp, "%-25s %8d %7.0f%% %8d\n",
			buf, pkt_counters[i].pc_interval, percent,
			pkt_counters[i].pc_total);
	}

	/*
	 * Calculate the total number of NFS packets this
	 * interval.
	 */
	nfstotal = pkt_counters[PKT_NFSWRITE].pc_interval +
		   pkt_counters[PKT_NFSREAD].pc_interval;

	/*
	 * Put out a header for the NFS counters.
	 */
	(void) fprintf(logfp, "#\n# nfs counters            %8s %8s %8s\n#\n",
		"int", "pct", "total");

	/*
	 * Print the NFS counters.  Percentage is calculated as
	 * packets this interval over total NFS packets this
	 * interval.
	 */

	for (i = 0; i < nnfscounters; i++) {
		if (nfstotal) {
			percent = ((float) nfs_counters[i].nc_interval /
				  (float) nfstotal) * 100.0;
		}
		else {
			percent = 0.0;
		}

		(void) sprintf(buf, "%s:", nfs_counters[i].nc_name);
		(void) fprintf(logfp, "%-25s %8d %7.0f%% %8d\t",
			buf, nfs_counters[i].nc_interval, percent,
			nfs_counters[i].nc_total);

		/*
		 * Print individual proc counters.
		 */
		(void) fputc('(', logfp);

		for (j = 0; j < MAXNFSPROC; j++) {
			if (j)
				(void) fputc('/', logfp);

			(void) fprintf(logfp, "%d", nfs_counters[i].nc_proc[j]);
		}

		(void) fprintf(logfp, ")\n");
	}

	/*
	 * Put out a header for the individual file counters.
	 */
	(void) fprintf(logfp, "#\n# file counters           %8s %8s %8s\n#\n",
		"int", "pct", "total");

	/*
	 * Print the individual file counters.  Percentage is
	 * calculated as packets this interval over total NFS
	 * packets this interval.
	 */
	for (i = 0; i < nfilecounters; i++) {
		if (nfstotal) {
			percent = ((float) fil_counters[i].fc_interval /
				  (float) nfstotal) * 100.0;
		}
		else {
			percent = 0.0;
		}

		(void) sprintf(buf, "%s:", fil_counters[i].fc_name);
		(void) fprintf(logfp, "%-25s %8d %7.0f%% %8d\t",
			buf, fil_counters[i].fc_interval, percent,
			fil_counters[i].fc_total);

		/*
		 * Print individual proc counters.
		 */
		(void) fputc('(', logfp);

		for (j = 0; j < MAXNFSPROC; j++) {
			if (j)
				(void) fputc('/', logfp);

			(void) fprintf(logfp, "%d", fil_counters[i].fc_proc[j]);
		}

		(void) fprintf(logfp, ")\n");
	}

	/*
	 * Put out a header for the NFS procs counters.
	 */
        if (showwhich == SHOWNFSPROCS) {
	    (void) fprintf(logfp, "#\n# nfs procs \n#\n");

	    (void) fprintf(logfp, "%s\n", nfsprocs_header);
	    tot_count = 0;

	    for (i = 0; i < MAXNFSPROC; i++) {
	        tot_count += prc_counters[i].pr_interval;
            }

	    for (i = 0; i < MAXNFSPROC; i++) { 
	        if (tot_count)
	           percent = (((float) prc_counters[i].pr_interval)
		     / ((float)tot_count)) * 100.0;
		else
		    percent = 0.0;

		(void) fprintf(logfp, "%-17s %5d  %3.0f%% %8d", local_procs[i],
		     prc_counters[i].pr_interval, percent, prc_counters[i].pr_total);
			    
	        count = prc_counters[i].pr_complete;

		if (count != 0) {
		    dcount = (double) count;
		    sum = prc_counters[i].pr_response;
		    sumsqr = prc_counters[i].pr_respsqr;

		    (void) fprintf(logfp, "   %8d  %8.2f", count, sum /dcount);

		    if (count > 1) {
		        (void) fprintf(logfp, "  %8.2f",
			    sqrt((dcount * sumsqr - sum * sum) /   (dcount * (dcount - 1.0)))); 
		    }
		    else {
		        (void) fprintf(logfp, "          ");
                    }
		    (void) fprintf(logfp, "  %8.2f", prc_counters[i].pr_maxresp);
	        }
	        (void) fprintf(logfp, "\n");
	    } 
        }
	/*
	 * End the log entry.
	 */
	(void) fprintf(logfp, "#\n# end\n#\n");
	(void) fflush(logfp);
}

#ifdef SUNOS5
/*
 * scrncpy - copy a curses array of chtype's (s2) to a character array (s1),
 *	     truncating or null padding to always copy n bytes.
 */
static char *
scrncpy(s1, s2, n)
chtype *s2;
char *s1;
int n;
{
	register char *os1;

	os1 = s1;

	n++;
	while ((--n != 0) && ((*s1++ = *s2++) != '\0'))
		;

	if (n != 0) {
		while (--n != 0)
			*s1++ = '\0';
	}

	return(os1);
}
#endif /* SUNOS5 */
