/*
    yamm, Yet Another Micro Monitor
    conf.c
    Copyright (C) 1992  Andrea Marangoni
    Copyright (C) 1994, 1995  Riccardo Facchetti

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <sys/utsname.h>
#include <sys/param.h>
#include <time.h>
#if defined(NCURSES)
# include "ncurses.h"
#else
# include <curses.h>
#endif /* NCURSES */

#include "yamm.h"

#define MEGA   (( double )(1024*1024))
#define KBYTES (( double )1024)

void Print_Conf( int nproc, struct pst_dynamic *dinfo )
{
	static int yet = 0;
	register int count;
	struct utsname buf;
	long conf;
	struct pst_static sbuf;

#if !defined(NO_CURSES)
	if ( look_lines() < 24 ) {
		curses_error( "Sorry, you must have at least 24 lines." );
		print_configuration = 0;
		return;
	}
#define PF (void)printw
#else
#define PF (void)printf
#endif /* !NO_CURSES */

	if ( !yet ) {

		if ( uname( &buf ) == -1 )
			( void )perror ( "uname" ), exit ( 1 );

		PF ( "\n\nSysname        : %s\n",
			buf.sysname );
		PF ( "Nodename       : %s\n",
			buf.nodename );
		PF ( "Release        : %s\n",
			buf.release );
		PF ( "Machine        : %s\n",
			buf.machine );

#if !defined(linux)
		PF ( "User           : " );
		switch ( *(buf.version) ) {
		case 'A':
			PF ( "Two-user system\n" );
		break;
		case 'B':
#if defined(hp9000s300) || defined(hp9000s400)  /* From "man uname" */
			PF ( "Unlimited-users system\n" );
#else
			PF ( "16-user system\n" );
#endif
		break;
		case 'C':
			PF ( "32-user system\n" );
		break;
		case 'D':
			PF ( "64-user system\n" );
		break;
		case 'E':
			PF ( "8-user system\n" );
		break;
		case 'U':
			PF ( "Unlimited-users system\n" );
		break;
		default:
			PF ( "??????\n" );
		break;
		}

		if ( *(buf.version+1) != '\0' )
			PF ( "Info Ver.      : %s\n",
				buf.version + 1);

		if ( ( conf = sysconf(_SC_CPU_VERSION )) == -1 )
			( void )perror ( "_SC_CPU_VERSION" ), exit ( 1 );

		switch ( conf ) {
		case CPU_PA_RISC1_0:
			PF ( "C.P.U          : HP Precision Architecture RISC Version 1.0\n" );
		break;
		case CPU_PA_RISC1_1:
			PF ( "C.P.U          : HP Precision Architecture RISC Version 1.1\n" );
		break;
		case CPU_HP_MC68020:
			PF ( "C.P.U          : Motorola MC68020\n" );
		break;
		case CPU_HP_MC68030:
			PF ( "C.P.U          : Motorola MC68020\n" );
		break;
		case CPU_HP_MC68040:
			PF ( "C.P.U          : Motorola MC68020\n" );
		break;
		default:
			PF ( "C.P.U          : ??????\n"  );
		break;
		}

#else
/*
 * Okay we know Linux is an Unlimited-user system, but yamm under HP-UX
 * display User field too, and it is nice remember that Linux is unlimited :)
 * - riccardo
 */
		PF ( "User           : Unlimited-user system\n" );
		PF ( "Version        : %s\n",
			buf.version);
		PF ( "C.P.U.         : %s\n",
			buf.machine);
#endif /* !linux */

/*
 * Some of this values are in limits.h
 */

		if ( ( conf = sysconf( _SC_CHILD_MAX )) == -1 )
			( void )perror ( "_SC_CHILD_MAX" ), exit ( 1 );

		PF ( "Max Proc.      : %ld ( Maximum number of simultaneous processes per user ID )\n" ,
			conf );

		if ( ( conf = sysconf( _SC_CLK_TCK )) == -1 )
			( void )perror ( "_SC_CLK_TCK" ), exit ( 1 );

		PF ( "Ticks          : %ld ( Number of clock intervals per second )\n",
			conf );
	
		if ( ( conf = sysconf( _SC_OPEN_MAX )) == -1 )
			( void )perror ( "_SC_OPEN_MAX" ), exit ( 1 );

		PF ( "Max open file  : %ld\n",
			conf );
	
		if ( ( conf = sysconf( _SC_JOB_CONTROL )) == -1 )
			( void )perror ( "_SC_JOB_CONTROL" ), exit ( 1 );

		PF ( "Job control    : %s ( System %s POSIX job control )\n",
			conf == -1 ? "No" : "Yes", conf == -1 ? "not support": "support"  );
		PS_stat ( &sbuf );

		PF ( "Max processes  : %ld ( Maximum number of total simultaneous processes )\n",
			sbuf.max_proc );
		PF ( "Page size      : %ld\n",
			sbuf.page_size );
		PF ( "Physical_memory: %ld Pages. ( %ld KBytes, %.2f MByte )\n",
			sbuf.physical_memory,
			sbuf.physical_memory*sbuf.page_size,
			( double )(sbuf.physical_memory*sbuf.page_size) / MEGA );
		PF ( "Boot time      : %s\n",
			ctime ( &sbuf.boot_time ) );

#if !defined(NO_CURSES)

		( void )curses_get_string ( "Type <RETURN> to see the signals recognized" );
		update_first_line ( nproc , dinfo);
#endif /* !NO_CURSES */

		PF ( "\nSignals recognized by the system :\n\n" );
		for ( count = 0; signames [ count ].signo; count++ )
			switch ( count % 3 ) {

			case 0:
				PF ( "%-12s : %2d", signames [ count ].name,
									signames [ count ].signo );
				break;

			case 1:
				PF ( "    |    %-12s : %2d",  signames [ count ].name,
											  signames [ count ].signo );
				break;

			case 2:
				PF ( "    |    %-12s : %2d\n",  signames [ count ].name,
												signames [ count ].signo );
				break;
			}

#if !defined(NO_CURSES)
		( void )curses_get_string("Type <RETURN> to see dynamic configuration");
		yet = 1;
		update_first_line ( nproc , dinfo);
#endif /* !NO_CURSES */
	} /* !yet */

#if !defined(NO_CURSES)
	PF ( "\n----------- DYNAMIC INFO ( Type <RETURN> to exit ) -----------\n\n" );
#else
	PF ( "\n\n----------- DYNAMIC INFO -----------\n\n" );
#endif /* !NO_CURSES */
	PF ( "Total virtual memory       : %-5ld Pages ( %s )\n",
		dinfo->psd_vm, get_dimension ( dinfo->psd_vm ) );

	PF ( "Active virtual memory      : %-5ld Pages ( %s )\n",
		dinfo->psd_avm, get_dimension ( dinfo->psd_avm ) );

	PF ( "Total real memory          : %-5ld Pages ( %s )\n",
		dinfo->psd_rm, get_dimension ( dinfo->psd_rm) );

	PF ( "Active real memory         : %-5ld Pages ( %s )\n",
		dinfo->psd_arm, get_dimension ( dinfo->psd_arm ) );

	PF ( "Free memory                : %-5ld Pages ( %s )\n",
		dinfo->psd_free, get_dimension ( dinfo->psd_free ));

#if defined(linux)

	PF ( "Shared memory              : %-5ld Pages ( %s )\n",
		dinfo->psd_shared, get_dimension ( dinfo->psd_shared ) );

	PF ( "Memory buffers             : %-5ld Pages ( %s )\n",
		dinfo->psd_buffers, get_dimension ( dinfo->psd_buffers ));
#endif /* linux */

	PF ( "Load average               : %.2f  %.2f  %.2f\n",
		dinfo->psd_avg_1_min, dinfo->psd_avg_5_min,
		dinfo->psd_avg_15_min );

#if !defined(linux)
	PF ( "Run queue length           : %ld\n",
		dinfo->psd_rq );
	PF ( "Jobs in disk wait          : %ld\n",
		dinfo->psd_dw );
	PF ( "Jobs in page wait          : %ld\n",
		dinfo->psd_pw );
	PF ( "Jobs sleeping in core      : %ld\n",
		dinfo->psd_sl );
	PF ( "Swapped out runnable jobs  : %ld\n",
		dinfo->psd_sw );
#endif /* !linux */

	( void )info_cpu( (long *) 0);
}


char *get_dimension ( long num_pages )
{
	static long dim_page = -1;
	static char result [ 8 ];
	double total_bytes;

	if ( dim_page == -1 ) {
		struct pst_static sbuf;

		PS_stat ( &sbuf );

		dim_page = sbuf.page_size;
	}
	
	total_bytes = num_pages * dim_page;
	
	if ( total_bytes >= MEGA ) {
		double mega = total_bytes / MEGA; 
/*
 * sprintf doesn't seem to work well in printing %f numbers, so
 * we do it with a trick.
 */
		 sprintf ( result, "%3d.%.2dM", ( int )mega,
			( int )( ( mega - ( int )mega ) * 100.00 ));

	} else
		sprintf ( result, "  %4.0fK", total_bytes / KBYTES );

	result [ 7 ] = '\0';
	return ( result );
}

#if !defined(linux)
#include <sys/dk.h>
#endif /* !linux */

/*
 * I don't known what some fields are, read the comments in dk.h
 * If you don't have dk.h comment it, the program will work
 * 
 *	In my dk.h:
 *		#define CPUSTATES       9
 *
 *		#define CP_USER         0  user mode of USER process
 *		#define CP_NICE         1  user mode of USER process at nice priority
 *		#define CP_SYS          2  kernel mode of USER process
 *		#define CP_IDLE         3  IDLE mode
 *		#define CP_WAIT         4  ????????
 *		#define CP_BLOCK        5  amount of time bocked on a spinlock
 *		#define CP_SWAIT        6  amount of time bocked on the kernel semaphore
 *		#define CP_INTR         7  INTERRUPT mode
 *		#define CP_SSYS         8  kernel mode of KERNEL process
 *
 */

/*
 * cpu_time !=0 for idle
 */
char *info_cpu( long *cpu_time )
{
/*
 * CPUSTATES defined in dk.h (HP-UX)
 *
 * You can find CPUSTATES and CP_* definitions in ../include/define.h (linux)
 */
#if defined(CPUSTATES)
	static long old [ CPUSTATES ];
	static long diff [ CPUSTATES ], total_change = 0L;
	static char localbuf[ 9 ];
	register long *tmp;
	register int count;
	double diff_idle;
	static int first_time = 1;

	if ( first_time ) {
		for ( count = 0; count < CPUSTATES; ++count )
			old [ count ] = 0L;
		first_time = 0;
		return ( " --.--%" );
	}

	if ( cpu_time ) {
		for ( count = total_change = 0, tmp = cpu_time;
			count < CPUSTATES; ++count, ++tmp ) {

			if ( (*tmp) < old [ count ] ) 	
/*
 * this only happens when the counter wraps
 * code stolen from top
 * - HV
 */
				diff [ count ] = (long)(( u_long ) (*tmp) - 
					( u_long )old [ count ] );
			else
				diff [ count ] = (*tmp) - old [ count ];

			old [ count ] = (*tmp);
			total_change += diff [ count ];

		}

		if ( total_change <= 0.0 )  /* problems */
			total_change = 1;

#if defined(CP_IDLE)
		diff_idle = (( double )diff [ CP_IDLE ] /
			( double )total_change )*100.00;

		/* sprintf seems don't well work "3.2f" */

		sprintf ( localbuf, "%3d.%.2d%%", ( int )diff_idle,
			( int )(( diff_idle - ( int )diff_idle )* 100.00 ));
#else
		strcpy ( localbuf, "???" );
#endif /* CP_IDLE */
		localbuf [ 8 ] = '\0';
		return ( localbuf );
	}
		
	PF ( "\n\n" );
#if defined(CP_USER)
	PF ( "CPU_USER %.2f%%    ",
		(( double )diff [ CP_USER ] / ( double )total_change )*100.00); 
#endif /* CP_USER */

#if defined(CP_NICE)
	PF ( "CPU_NICE %.2f%%    ",
		(( double )diff [ CP_NICE ] / ( double )total_change )*100.00);
#endif /* CP_NICE */

#if defined(CP_SYS)
	PF ( "CPU_SYS %.2f%%    ",
		(( double )diff [ CP_SYS ] / ( double )total_change )*100.00);
#endif /* CP_SYS */

#if defined(CP_IDLE)
	PF ( "CPU_IDLE %.2f%%    ",
		(( double )diff [ CP_IDLE ] / ( double )total_change )*100.00);
#endif /* CP_IDLE */
	PF ( "\n" );

#if defined(CP_WAIT)
	PF ( "CPU_WAIT %.2f%%    ",
		(( double )diff [ CP_WAIT ] / ( double )total_change )*100.00);
#endif /* CP_WAIT */

#if defined(CP_BLOCK)
	PF ( "CPU_BLOCK %.2f%%    ",
		(( double )diff [ CP_BLOCK ] / ( double )total_change )*100.00);
#endif /* CP_BLOCK */

#if defined(CP_SWAIT)
	PF ( "CPU_SWAIT %.2f%%    ",
		(( double )diff [ CP_SWAIT ] / ( double )total_change )*100.00);
#endif /* CP_SWAIT */

#if defined(CP_INTR)
	PF ( "CPU_INTR %.2f%%    ",
		(( double )diff [ CP_INTR ] / ( double )total_change )*100.00);
#endif /* CP_INTR */
	PF ( "\n" );

#if defined(CP_SSYS)
	PF ( "CPU_SSYS %.2f%%    ",
		(( double )diff [ CP_SSYS ] / ( double )total_change )*100.00);
#endif /* CP_SSYS */
	PF ( "\n" );
#endif /* CPUSTATES */
	return ( " --.--%" );
}
