/*
# The software provided here is released by the National
# Institute of Standards and Technology (NIST), an agency of
# the U.S. Department of Commerce, Gaithersburg MD 20899,
# USA.  The software bears no warranty, either expressed or
# implied. NIST does not assume legal liability nor
# responsibility for a User's use of the software or the
# results of such use.
# 
# Please note that within the United States, copyright
# protection, under Section 105 of the United States Code,
# Title 17, is not available for any work of the United
# States Government and/or for any works created by United
# States Government employees. User acknowledges that this
# software contains work which was created by NIST employees
# and is therefore in the public domain and not subject to
# copyright.  The User may use, distribute, or incorporate
# this software provided the User acknowledges this via an
# explicit acknowledgment of NIST-related contributions to
# the User's work. User also agrees to acknowledge, via an
# explicit acknowledgment, that any modifications or
# alterations have been made to this software before
# redistribution.
*/
# define O_LARGEFILE 0
# include <stdlib.h>
# include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
# include <time.h>



/*****************************************************************
Compute elapsed time and close a log file
*****************************************************************/
void log_close (FILE *log, /* log file */
		time_t from /* time program started running */)
{
	time_t		till; /* time program finished (actually time log_close called) */
	unsigned long	et, /* elapsed time (program run time: seconds of wall clock) */
			tmin, /* total minutes running */
			min, /* minutes for elapsed time after whole hours deducted */
			sec, /* seconds of elapsed run time after hours & minutes */
			hours; /* hours of elapsed time */

	time(&till); /* get current time */
	et = till - from; /* elapsed time in seconds */
	tmin = et/60; /* elapsed time in minutes */
	sec = et%60; /* fraction of last minute in seconds */
	hours = tmin/60; /* hours elapsed time */
	min = tmin%60; /* fraction of last hour in whole minutes */
   
	fprintf (log,"run start %s",ctime(&from));
	fprintf (log,"run finish %s",ctime(&till));

	fprintf (log,"elapsed time %lu:%lu:%lu\n",hours,min,sec);
}


/*
CMD: dsumm TTT HHH UUU /dev/sdb DF
Case: TTT
Host: HHH
User: UUU
Device: /dev/sdb
Label: DF
Comment: 
static char *SCCS_ID[] = {"@(#) dsumm.c Linux Version 1.4 Created 01/26/09 at 14:01:26",
				__DATE__,__TIME__};
*/
char *sccs_id = "@(#) dsumm.c Version 1.5 created 07/09/09 at 15:21:33";
/***** Author: Dr. James R. Lyle, NIST/SDCT/SQG ****/

	int n_cols = 3;

int init (int np, char *p[],FILE *f)
{
	long long test;
	int	i;

	if ((np < 7) || (np > 8)){
		f = stderr;
		fprintf (f,"Missing or extra parameter\n");
		fprintf (f,"CMD: ");
		for (i = 0 ; i < np; i++) fprintf (f," %s",p[i]);
		fprintf (f,"\n");
		fprintf (f,"Usage: dsumm case host user {device|-} label {log_file|-} n_columns\n");
		exit (1);
	}
	if (np == 8){
		sscanf (p[7],"%d",&n_cols);
		if ((n_cols < 1) || (n_cols > 5)){
			fprintf (stderr,"Bad value (%d) for n_columns (1..5)\n",n_cols);
			exit(1);
		}
	}

	if (f == NULL){
		printf ("%s Failed to open log file: %s\n",p[0],p[6]);
		exit (1);
	}
	fprintf (f,"Starting Analysis ...\n");
	 printf ("Output to %s\n",p[6][0] == '-'?"stdout":p[6]);
	if (sizeof(test) != 8){
		f = stderr;
		fprintf (f,"Data type too small ");
		fprintf (f,"long long is %d\n",sizeof(test));
		fprintf (f,"long is %d\n",sizeof(long));
		exit(1);
	}
	if (sccs_id[0] == '%') fprintf (f,"Development version of %s ",p[0]);
	fprintf (f,"%s\n",sccs_id);
	fprintf (f,"Compiled with gcc version %s on %s at %s\n",
		__VERSION__,__DATE__,__TIME__);
	fprintf (f,"CMD: ");
	for (i = 0 ; i < np; i++) fprintf (f," %s",p[i]);
	fprintf (f,"\n");

	fprintf (f,"Case: %s\n",p[1]);
	fprintf (f,"Host: %s\n",p[2]);
	fprintf (f,"User: %s\n",p[3]);
	fprintf (f,"Device: %s%s\n",p[4],(p[4][0] == '-')?" (stdin)":"");
	fprintf (f,"Label: %s\n",p[5]);
	fprintf (f,"Output: %s\n",p[6][0] == '-'?"stdout":p[6]);
	return 0;
}


main (int np, char *p[]){

	long long test, count[256],ascii_count[256],total = 0,sectors,more,
		n_printable = 0,at = 0;
	int	k,i,n,nnl,seen = 0,line = 0, max_line = 60;
	int	alt = 0,printable,input;
	unsigned char buff[512];
	FILE *f = stdout;
	time_t		from; /* time program started */

	/*
	f = fopen ("wipe-analysis.txt","w");
	f = stdout;
	*/
	if (np == 7){
		if (p[6][0] == '-') f = stdout;
		else f = fopen (p[6],"w");
	}
	else f = stderr;

	init (np,p,f);
	input = 0;
	if (p[4][0] != '-'){ /* input is a file to open */
		input = open (p[4],O_RDONLY);
/*		printf ("Open: %s as %d\n",p[4],input); */
		if (input == -1){
			fprintf (stderr,"Unable to open file %s: ",p[4]);
			perror(NULL);
			exit(1);
		}
	}
	time(&from); /* get current time */
	for (i = 0; i < 256; i++) count[i] = 0;
	for (i = 0; i < 256; i++) ascii_count[i] = 0;
	while (n=read (input,buff,512)){
		printable = 0;
		for (i = 0; i < n; i++){
			count[buff[i]]++;
			if ((buff[i] > ' ') && (buff[i] <= '~')) printable = 1;
		}
		if (printable) {
			n_printable++;
			for (i = 0; i < n; i++) ascii_count[buff[i]]++;
		}
		/*
		fprintf (f,"Read %lld %s of %lld\n",at,printable?"Printable":"erased",n_printable);
		*/
		if (printable && (n_printable == 1)){
			fprintf (f,"\nSector %lld is first sector with printable text\n",at);
			fprintf (f,"============= Start text =============\n");
			line = 0;
			nnl = 0;
			for (i = 0; i < n; i++){
				if (buff[i] == '\n'){
					fprintf (f,"\n");
					line = 0;
				}
				else if ((buff[i] >= ' ') && (buff[i] <= '~')){
					fprintf (f,"%c",buff[i]);
					line++;
					if (line >= max_line){
						line = 0;
						nnl++;
						fprintf (f,"\n");
					}
				}
			}
			if (line) {nnl++; fprintf (f,"\n");}
			fprintf (f,"============= End text Sector %lld =============\n",at);
			if (nnl) fprintf (f,"%d <new line> character%s inserted for readability\n\n",nnl,(nnl==1)?"":"s");

		}
		at++;
	}
	if (alt){ /* ??? looks like "then" part is for debugging?  */
		for (i = 0; i < 64; i++){
			if (count[i]+count[i+64]+count[i+2*64]+count[i+3*64]){
				for (k = 0; k < 4; k++){
					total += count[i+k*64];
					fprintf (f,"%12lld %02X ",count[i+k*64],i+k*64);
					if ((i+k*64 > '~') || (i+k*64 < ' '))
						fprintf (f,"    ");
					else fprintf (f,"(%c) ",i+k*64);
				}
				fprintf (f,"\n");
			}
		}
	}
	else {
		fprintf (f,"Totals for all sectors\n");
		fprintf (f,"summary format: <count> <hex value> <(actual character if printable)> ...\n");
		n = 0;
		total = 0;
		for (i = 0; i < 256; i++){
			if (count[i] /*   || (count[i]==0)*/){
				n++;
				seen++;
				total += count[i];
				fprintf (f,"%12lld %02X ",count[i],i);
				if ((i > '~') || (i < ' '))
					fprintf (f,"    ");
				else fprintf (f,"(%c) ",i);
			}
			if (n==n_cols){
				n = 0;
				fprintf (f,"\n");
			}
		}
		if(n)fprintf (f,"\n");
		fprintf (f,"Totals for non-ASCII sectors\n");
		fprintf (f,"summary format: <count> <hex value> <(actual character if printable)> ...\n");
		n = 0;
		for (i = 0; i < 256; i++){
			if (count[i]-ascii_count[i] /*   || (count[i]==0)*/){
				n++;
				fprintf (f,"%12lld %02X ",count[i]-ascii_count[i],i);
				if ((i > '~') || (i < ' '))
					fprintf (f,"    ");
				else fprintf (f,"(%c) ",i);
			}
			if (n==n_cols){
				n = 0;
				fprintf (f,"\n");
			}
		}
		if(n)fprintf (f,"\n");
	}
		fprintf (f,"\n");

	fprintf (f,"%lld bytes, %lld sectors",total,total/512);
	if (total%512) fprintf (f,"+%lld bytes (partial sector)",total%512);
	fprintf (f,", %d distinct values seen\n",seen);
	if (n_printable)
		fprintf (f,"%lld sector%s printable text\n",n_printable,(n_printable==1)?" has":"s have");
	else fprintf (f,"No sectors have printable text\n");
	fprintf (f,"\n");
	log_close (f,from);
	fprintf (f,"... done\n");
}
