/* static char *sccsid = "@(#) Patrick Strode vixen.c %M% %I% %H%"; */
static char *sccsid = "@(#) Patrick Strode    vixen.c 1.0    05/23/95 09:00:37";

/*
 *
 * vixen for linux
 *
 * Patrick Strode - pstrode@execpc.com
 *
 * Monitors in real-time:
 *   disk space status            based on dfmon(8) by Ed Carp
 *   memory status                based on top(1)
 *   network interface status     based on netstat(8)
 *
 * Requires gcc 2.5.8 or better
 * Requires ncurses 1.9.1 or better
 *
 * Copyright Policy: GPL
 *
 * usage:  vixen [-t THRESH] [-s secs]
 *
 *
 */
#include <stdio.h>
#include <ncurses/curses.h>
#include <signal.h>
#include <sys/types.h>
#include <utmp.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <linux/fs.h>
#include <linux/vfs.h>
#include <linux/termios.h>
#include <mntent.h>
#include <unistd.h>
#include <linux/fcntl.h>
#include <sys/time.h>
#include <ncurses/termcap.h>

/* Netstat module includes */
#include <linux/if.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
#include <linux/net.h>
#include <linux/tcp.h>
#include <errno.h>

/* File defines */
#define LOAD_FILE "/proc/loadavg"
#define MEM_FILE "/proc/meminfo"
#define UPTIME_FILE "/proc/uptime"
#define STAT_FILE "/proc/stat"
#define NETDEV_FILE "/proc/net/dev"
#define UTMP_FILE "/etc/utmp"

#define LMAX sizeof(utmp.ut_line)
struct utmp *utm, *getutent ();
struct statfs buf;
struct mntent mnt;
float atof ();
char lname;                       /* Login name */
int delay = 5;                    /* Default delay used for display */
float Sleeptime = 5;              /* Sleep time used in delay loop */
float thresh = 90.0;              /* Default threshold */
float pthresh = 90.0;             /* Default partition threshold */
float inthresh = 90.0;            /* Default partition threshold input*/
int pcount = 0;                   /* Number of partitions in mtab*/
int ppart = 0;                    /* Partition number being updated */
int new_pthresh = 0;              /* Update fsthresh array flag: */
                                  /*     0 = no update           */
                                  /*     1 = update array        */
char fstype[32], *fst;            /* FS type in MTAB             */
int new_view = 0;                 /* Update file system view flag: */
                                  /*     0 = no update             */
                                  /*     1 = update fs view        */ 
int new_mode = 0;                 /* Update header area of display */
                                  /*     0 = no update             */
                                  /*     1 = update header area    */ 
int new_color = 0;                /* Update header area of display */
                                  /*     0 = no update             */
                                  /*     1 = update header area    */ 
int mthresh = 250;                /* Memory threshold              */
int malarm = 0;                   /* Below memory threshold        */
int sthresh = 250;                /* Swap threshold                */ 
int salarm = 0;                   /* Below swap threshold          */

#define LFNMAX 32
#define MTAB MOUNTED
extern char *optarg;
extern int optind;

/* Time structure */
extern struct tm *localtime();
struct tm actual;              /* Actual (current) time */
time_t session_start;          /* Start of monitor session */ 
double elapsed;                /* Current length of monitor session */


void end(void);
void stop(void);
void do_key(char c);           /* Process key input */
void get_part(void);           /* Get partition input */
void chg_mode(void);           /* Change FS mode - global/partition */
void chg_sound(void);          /* Toggle sound on/off */
void chg_dcolor(void);         /* Toggle color on/off */
void chg_display(void);        /* Change FS display mode */
void set_global_thresh(void);  /* Set the global FS threshold */
void set_mem_thresh(int mode); /* Set the free memory threshold */
void set_swap_thresh(int mode);/* Set the free swap threshold */

/* Terminal control */
struct termio Savetty;         /* The original terminal attributes. */
struct termio Rawtty;          /* The new terminal attributes. */
char *cm, *cl, *clrtoeol, *ho; 
struct termio newtty;

/* Help screen info */
/* The response to the interactive 'h' command. */
#define HELP_SCREEN "\
Interactive commands are:         v Version information\n\
m Show memory stats               t Set global threshold level\n\
n Show network interface stats    i Set delay in seconds between updates\n\
c Clear stats area                p Set partition threshold level\n\
d Toggle FS display               s Switch between Global & Partition modes\n"

/* Version screen info */
/* The response to the interactive 'v' command. */
#define VER_SCREEN "\
Version Information:\n\
\n\
              Vixen 1.0\n\
              Copyright 1995 - Patrick Strode\n\
              pstrode@execpc.com\n\
 
\n"

/* Memory information */
unsigned show_meminfo(int mode);  /* Display memory stats */

/* Monitor modes */
int MODE = 0;
int BKGD_MEM = 0;
int BKGD_SWAP = 0;
int THRESH_CHK = 0;
int FS_DISPLAY = 0;
int MEM_MODE = 1;
int SWAP_MODE = 1;
int THRESH_SND = 0;
int COLOR_OK = 0;
int COLOR_DO = 0;
#define FS_GLOBAL     0         /* Display file system info      */
#define FS_PARTITION  1         /* Display other file sys info   */
#define THRESH_G      0         /* Threshold checking globally   */
#define THRESH_P      1         /* Threshold check by partition  */
#define SHOW_NOTHING  0         /* Show only file system stats   */
#define SHOW_MEMORY   1         /* Show memory stats             */
#define SHOW_NET      2         /* Show network interface stats  */
#define SHOW_HELP     3         /* Show help screen              */
#define SHOW_VER      4         /* Show version information      */
#define SHOW_SWITCH   5         /* Not currently used            */
#define QUIET         0         /* Run modules in quiet mode     */
#define VERBOSE       1         /* Run modules in normal mode    */ 
#define BKGD          0         /* Run in background (no display */
#define FRGD          1         /* Run normally w/ display       */
#define SOUND_OFF     0         /* Sound is off                  */
#define SOUND_ON      1         /* Sound is on                   */              
#define COLOR_NO      0         /* Do not use color              */
#define COLOR_YES     1         /* Use color                     */

#define CLR_NORMAL    1         /* Normal color        */
#define CLR_WARNING   2         /* Warning             */
#define CLR_FS        3         /* File system display */
#define CLR_MEM       4         /* Memory display      */
#define CLR_NET       5         /* Network display     */
#define CLR_HELP      6         /* Help display        */
#define CLR_ASK       7         /* Question display    */
#define CLR_MONO      8         /* Monochrome          */

/* Uptime module stats */
static char upt[128];
static char sess[128];
double av[3];
char *sprint_uptime(void);     /* Display uptime information */
char *sprint_session(void);    /* Display session information */
void loadavg(double *av1, double *av5, double *av15); /* Load avg */
void uptime(double *uptime_secs, double *idle_secs);  /* Uptime   */


/* Netstat module stats */
int skfd;
#define E_READ  -1
#define E_PARA  -2
#define E_IOCTL -3
static int iface_info(void);    /* Interface information */

struct interface {
  char name[IFNAMSIZ];					/* interface name       */
  short flags;                  /* various flags        */
  int metric;										/* routing metric       */
  int mtu;											/* MTU value            */
  struct sockaddr addr;					/* IP address           */
  struct sockaddr dstaddr;			/* P-P IP address       */
  struct sockaddr broadaddr;		/* IP broadcast address */
  struct sockaddr netmask;			/* IP network mask      */
  struct sockaddr hwaddr;				/* HW address           */
  struct enet_statistics stats;	/* statistics           */
};

/* ***** Main ***** */
main (argc, argv)
int argc;
char **argv;
{
  FILE *f;                  /* Mtab */
  int c, uflag = 0, mailflag = 0, i = 0, once = 0, xflag = 0,
      j = 0, k = 0, p = 0, skip;


  char line[512], *linep;   /* Line to be read in */

  char fs[LFNMAX], *fsp;  	/* File system */

  char mounted[LFNMAX], scratch[LFNMAX], *mountedp;   /* mounted */

  char *users[64];          /* users to mail */

  char *exclude[64];        /* file systems to exclude */

  int Max_Mount = 20;       /* Maximum partitions */
  float usedp;              /* Used percentage of file system */
  float npeak[Max_Mount];   /* Peak used percentage of file system */
  float lpeak[Max_Mount];   /* Low usage point of file system */
  float fsthresh[Max_Mount];/* Disk space threshold based on fs */
  long Ttotal = 0;          /* Total blocks of mounted file system */
  long Ftotal = 0;          /* Total free blocks of mounted file sys */
  long Atotal = 0;          /* Total avail. blocks of mounted file sys */
  long Utotal = 0;          /* Total used blocks of mounted file sys */
  /* char ths[5]; */
  char chkfstype[32];

	time_t mclock = time ( ( time_t *)0 );  /* Get time */

	unsigned int main_mem;    /* Main memory */

  char y;                   /* Presed key passed to do_key() */

  struct timeval tv;
  fd_set in;
  char *termtype;           /* Terminal type */
  char tmpbuf[65];          /* Used to store host name */
 
  /* Netstat */
  int z;                    /* Counter for interfaces */

  users[0] = NULL;
  cuserid(&lname);          /* Get login name */

 /* Get the command args now */
  while ((c = getopt (argc, argv, "os:t:u:x:")) != EOF)
  {
    switch (c)
    {
    /*
    case 'o':
      once = 1;
      uflag = 1;
      break;
		*/
    case 's':                  /* Set update interval */
      delay = atoi (optarg);
      break;
    case 't':                  /* Set threshold */
      thresh = atof (optarg);
  		/* strcpy (ths,optarg); */
      break;
		/*
    case 'u':  */              /* Set user to notify */
    /*  delay = 60;
        uflag = 1;
        users[i++] = optarg;
        break;
		*/
    case 'x':                  /* Set excludes */
      xflag = 1;
      exclude[j++] = optarg;
      break;
    }
  }

	if (uflag == 0) {
  	close(0); 
	  if (open("/dev/tty", O_RDONLY)) {
			printf("stdin is not there\n"); 
			exit(1);
		}
 	 if (ioctl(0, TCGETA, &Savetty) == -1) {
		 	printf("ioctl() failed"); 
			exit(1);
 	 }
 	 newtty = Savetty;
 	 newtty.c_lflag &= ~ICANON;
 	 newtty.c_lflag &= ~ECHO;
 	 newtty.c_lflag &= ~ISIG;
 	 newtty.c_cc[VMIN] = 1;
 	 newtty.c_cc[VTIME] = 0;
 	 if (ioctl(0, TCSETAF, &newtty) == -1) {
			printf("cannot put tty into raw mode\n");
			exit(1);
 	 }
 	 ioctl(0, TCGETA, &Rawtty);     /*  Go to raw mode */
	
 	/*
 	 * Get termcap entries and window size.
 	 */
 	 tgetent(NULL, termtype);
 	 cm = tgetstr("cm", 0);
 	 /* clrtobot = tgetstr("cd", 0); */
 	 cl = tgetstr("cl", 0);
 	 clrtoeol = tgetstr("ce", 0);
 	 ho = tgetstr("ho", 0);
	
 	/*
 	 * Set up signal handlers.
 	 */
 	/* signal(SIGTERM,SIG_IGN); */
 	 signal(SIGHUP, (void *)(int) end);
 	 signal(SIGINT, (void *)(int) end);
 	 signal(SIGTSTP, (void *)(int) stop);
 	/*  signal(SIGWINCH, (void *)(int) window_size); */
 }

 /* Set the watermark arrays to default values */
  for ( p = 0; p < Max_Mount; p++) npeak[p] = 0.0;
  for ( p = 0; p < Max_Mount; p++) lpeak[p] = 100.0;
  for ( p = 0; p < Max_Mount; p++) fsthresh[p] = thresh;

  users[i] = NULL;
  exclude[j] = NULL;
  gethostname(tmpbuf,65);
  if (once == 1)
    printf ("%12s            BSIZE   1KBLKS   AVAIL USED  USED   PEAK\n\n",
	    "DEVICE      MOUNT POINT ");
  if (uflag == 0)
  {
		actual = *localtime ( &mclock ); 
		session_start = time(NULL);
    initscr ();
    start_color();
    COLOR_OK = has_colors();
    if (COLOR_OK) {
			init_pair(CLR_ASK, COLOR_WHITE, COLOR_BLACK);   /* White on black */
			init_pair(CLR_WARNING, COLOR_RED, COLOR_BLACK);     /* Red on black */
			init_pair(CLR_NORMAL, COLOR_GREEN, COLOR_BLACK);   /* Green on black */
			init_pair(4, COLOR_BLUE, COLOR_BLACK);    /* Blue on black */
			init_pair(CLR_FS, COLOR_CYAN, COLOR_BLACK);    /* Cyan on black */
			init_pair(CLR_NET, COLOR_YELLOW, COLOR_BLACK);  /* Yellow on black */
			init_pair(CLR_MEM, COLOR_MAGENTA, COLOR_BLACK); /* Magenta on black */
			init_pair(CLR_MONO, COLOR_WHITE, COLOR_BLACK);   /* White on black */
			attrset(COLOR_PAIR(CLR_NORMAL));
			COLOR_DO = COLOR_YES;
		}
    curs_set(0); 
   /* 
    nocbreak();
    noecho();
    */
    attron(A_REVERSE);
    move (0, 1);
    printw ("%-20s Session: %-20s                       " ,
		tmpbuf,sprint_session());
    move (1, 1);
    printw ("Interval: %-4i sec   Threshold: %6.2f %%                              Global ",delay,thresh);
    move (2, 1);
    printw ("----------------------- FILE SYSTEMS ----------------------- -- PERCENT --   ");
    move (3, 1);
    printw ("DEVICE      MOUNT POINT       BSIZE   1KBLKS   AVAIL    USED   USED   PEAK   ");
    attroff(A_REVERSE);
    move (24, 0);
  	printw ("Quit-q   Help-h   %s " ,sprint_uptime());
  }
  while (1)
  {
    move (0, 65);
    attron(A_REVERSE);
    printw ("<Updating>   ");
    attroff(A_REVERSE);
    refresh();
    sleep(1);
    move (0, 65);
    attron(A_REVERSE);
    printw ("             ");
    attroff(A_REVERSE);
    if (uflag == 0)
      move (4, 0);
    if ((f = fopen (MTAB, "r")) == (FILE *) NULL)
    {
      fprintf (stderr, "can't open %s!\n", MTAB);
      if (uflag == 0)
				endwin ();
      exit (1);
    }
    p = 0;
    pcount = 0;
    Ttotal = 0;
    Ftotal = 0;
    Atotal = 0;
    Utotal = 0;
    while (fgets (line, 510, f) != (char *) NULL)
    {
      sscanf (line, "%s %s %s %s %s %s", fs, mounted, fstype, scratch, scratch, scratch);
/*
 * fprintf(stderr, "DEBUG: mounted='%s', fs='%s'\n", mounted, fs); 
 */
 			/* Do not process proc file system type */
 			strcpy(chkfstype,"proc");
	   	if (strcmp (fstype, chkfstype) == 0) {
	   		continue;
	   	}

 			/* Do not process iso9660 (cdrom) file system */
 			strcpy(chkfstype,"iso9660");
	   	if (strcmp (fstype, chkfstype) == 0) {
	   		continue;
	   	}
 			/* Do not process /dev/fd0 (floppy drive) file system */
 			strcpy(chkfstype,"/dev/fd0");
	   	if (strcmp (fs, chkfstype) == 0) {
	   		continue;
	   	}
 			/* Do not process /dev/fd1 (floppy drive ) file system */
 			strcpy(chkfstype,"/dev/fd1");
	   	if (strcmp (fs, chkfstype) == 0) {
	   		continue;
	   	}

      if (EOF == statfs (mounted, &buf))
				perror (mounted);
      else
      {
#ifdef DEBUG
				fprintf (stderr, "%s: type=0x%lx, bsize=%ld, blocks=%ld, bfree=%ld, bavail=%ld, files=%ld, ffree=%ld\n",
		 		mounted, buf.f_type, buf.f_bsize, buf.f_blocks, buf.f_bfree, buf.f_bavail,
		 		buf.f_files, buf.f_ffree);
#endif

				i = buf.f_bsize / 1024L;
				if (buf.f_blocks == 0L)  {
	  			usedp = 0.0;
	  			npeak[p] = 0.0;
	  			lpeak[p] = 0.0; }
				else 
	  			usedp = 100.0 * ((float) buf.f_bavail / (float) buf.f_blocks); 
				usedp = 100.0 - usedp;
				if (p <= Max_Mount) {
					if (usedp >= npeak[p])
						npeak[p] = usedp;
  				if (usedp <= lpeak[p])
    				lpeak[p] = usedp;
				}
				if ((COLOR_OK) && (COLOR_DO == COLOR_YES)) {
					attrset(COLOR_PAIR(CLR_FS));
				}
				if (uflag == 0 || once == 1) {
					if (FS_DISPLAY == FS_GLOBAL) {
	  				printw ("%10s   %-17s %5d  %7ld %7ld %7ld",
		  			fs, mounted, buf.f_bsize, i * buf.f_blocks,
		  			i * buf.f_bavail, i * (buf.f_blocks - buf.f_bfree));
					}
					else {
						if (FS_DISPLAY == FS_PARTITION) {
	  					printw ("%10s   %-17s %5s   %2d  %7ld    %6.2f",
		  				fs, mounted, fstype, pcount, i * buf.f_bavail,
		  				fsthresh[pcount]);
						}
					}
		  		if (THRESH_CHK == THRESH_G) {
    				if (usedp >= thresh && buf.f_blocks > 0) {
							attron(A_BLINK);  
							attron(A_BOLD);  
						}
					}
					else {
						if (THRESH_CHK == THRESH_P) {
							if (usedp >=fsthresh[p] && buf.f_blocks > 0) {
								attron(A_BLINK);  
								attron(A_BOLD);  
							}
						}
					}
	  			printw (" %6.2f ",usedp);
		  		if (THRESH_CHK == THRESH_G) {
    				if (usedp >= thresh && buf.f_blocks > 0) {
							attroff(A_BLINK); 
							attroff(A_BOLD); 
						}
					}
					else {
						if (THRESH_CHK == THRESH_P) {
							if (usedp >=fsthresh[p] && buf.f_blocks > 0) {
								attroff(A_BLINK);  
								attroff(A_BOLD);  
							}
						}
					}
	  			printw ("%6.2f", npeak[p]);
		  	}
  			Ttotal = Ttotal + (i * buf.f_blocks);
  			Ftotal = Ftotal + (i * buf.f_bfree);
  			Atotal = Atotal + (i * buf.f_bavail);
  			Utotal = Utotal + (i * (buf.f_blocks - buf.f_bfree));
				if (uflag == 1 && once == 0    /*
				        * && mailflag == 0 
				        */  && usedp > thresh && buf.f_blocks > 0)
				{
#ifdef DEBUG
	  			fprintf (stderr, "over thresh, fs=%s\n", mounted);
#endif
	  			skip = 0;
	  			i = 0;
	  			while (exclude[i] != NULL)
	  			{
#ifdef DEBUG
	    			fprintf (stderr, "skip check, fs=%s, exclude=%s\n", mounted, exclude[i]);
#endif
	    			if (strcmp (exclude[i], mounted) == 0)
	    			{
#ifdef DEBUG
	      			fprintf (stderr, "skip set, fs=%s\n", mounted);
#endif
	      			skip = 1;
	      			break;
	    			}
	    			i++;
	  			}
	  			i = 0;
	  			while (users[i] != NULL && skip == 0)
	  			{
	    			sprintf (line,
		     			"partition %s is %6.2f %% full\7",
		     			mounted, usedp);
#ifdef DEBUG
	    			fprintf (stderr, "notifying %s\n", users[i]);
#endif
	    			writetty (users[i], line);
	    			i++;
	  			}
				}
    	}
    	if (THRESH_CHK == THRESH_G) {
      	if (usedp > thresh && uflag == 0 && buf.f_blocks > 0) {
					attron(A_BOLD);
					if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
						attrset(COLOR_PAIR(CLR_WARNING));
					}
					printw (" ** ");
					if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
						attrset(COLOR_PAIR(CLR_NORMAL));
					}
					attroff(A_BOLD);
      	}
      	else {
      	  if (uflag == 0) {
						printw ("    ");
					}
				}
			}
			else {
			  if (THRESH_CHK == THRESH_P) {
					if (usedp > fsthresh[p] && uflag == 0 && buf.f_blocks > 0) {
						attron(A_BOLD);
						if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
							attrset(COLOR_PAIR(CLR_WARNING));
						}
						printw (" ** ");
						if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
							attrset(COLOR_PAIR(CLR_NORMAL));
						}
						attroff(A_BOLD);
      		}
      		else {
      		  if (uflag == 0) {
							printw ("    ");
						}
					}
			  }
			}
      if (uflag == 0)
				printw ("\n");
      if (once == 1)
				printf ("\n");
			p++;
			pcount++;
    }
    if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
			attrset(COLOR_PAIR(CLR_NORMAL));
		}
    pcount--;
    if (FS_DISPLAY == FS_GLOBAL) {
			printw ("                                      ------- ------- -------\n");
			printw (" Totals:                              %7ld %7ld %7ld",Ttotal,Atotal,Utotal);
		}
		else {
			printw ("                                                             \n");
			printw ("                                                               ");
		}
  	mclock = time ( ( time_t *)0 );
		actual = *localtime ( &mclock ); 

  	move (0, 1);
  	attron(A_REVERSE);
    printw ("%-20s Session: %-20s                       " ,
		tmpbuf,sprint_session());
  	attroff(A_REVERSE);

		if (MODE == SHOW_HELP) {
			move (17,0);
			printw("%s",HELP_SCREEN);
			refresh();
		}
		else {
			if (MODE == SHOW_VER) {
				move (17,0);
				printw("%s",VER_SCREEN);
				refresh();
			}
			else {
				if (MODE == SHOW_MEMORY) {
	  			main_mem = show_meminfo(VERBOSE);
				}
				else {
					if (MODE == SHOW_NET) {
						z = iface_info();
					}
					else {
						move (17,0);
						clrtobot ();
					}
				}
			}
		}
    if (uflag == 0)
    {
      clrtobot (); 
      refresh ();
    }
    fclose (f);
    if (once == 1)
      break;
    /* sleep (delay); */


  	move (24, 0);
  	printw ("Quit-q   Help-h    %s " ,sprint_uptime());
		refresh();

		/* sleep & wait for keyboard input */
		tv.tv_sec = Sleeptime;
		tv.tv_usec = (Sleeptime - (int)Sleeptime) * 1000000;
		FD_ZERO(&in);
		FD_SET(0, &in); 
	  if (select(16, &in, 0, 0, &tv) > 0 && read(0, &y, 1) == 1) 
	     do_key(y); 

		if (new_pthresh == 1) {
			fsthresh[ppart] = inthresh;
			new_pthresh = 0;
		}
		if (new_mode == 1) {
			new_mode = 0;
			if (new_color == 1) {
				if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
					attrset(COLOR_PAIR(CLR_NORMAL));
				}
				else { 
					if (COLOR_OK) {
						attrset(COLOR_PAIR(CLR_MONO));
					}
				}
			}
  		attron(A_REVERSE);
  		move (0, 1);
    	printw ("%-20s Session: %-20s                       " ,
			tmpbuf,sprint_session());
  		attroff(A_REVERSE);
			if (THRESH_CHK == THRESH_G) {
 		   	attron(A_REVERSE);
    		move (1, 1);
    		printw ("Interval: %-4i sec   Threshold: %6.2f %%                              Global ",delay,thresh);
 		   	attroff(A_REVERSE);
 		   	move (24, 0);
 		   	refresh();
			}
			else {
			  if (THRESH_CHK == THRESH_P) {
 		   		attron(A_REVERSE);
    			move (1, 1);
    			printw ("Interval: %-4i sec   Threshold: %6.2f %%                           Partition ",delay,thresh);
 		   		attroff(A_REVERSE);
 		   		move (24, 0);
 		   		refresh();
			  }
			}
		}
		if (new_view == 1) {
			new_view = 0;
			if (new_color == 1) {
				new_color = 0;
				if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
					attrset(COLOR_PAIR(CLR_NORMAL));
				}
				else { 
					if (COLOR_OK) {
						attrset(COLOR_PAIR(CLR_MONO));
					}
				}
			}
			move (0,1);
  		attron(A_REVERSE);
    	printw ("%-20s Session: %-20s                       " ,
			tmpbuf,sprint_session());
  		attroff(A_REVERSE);
			if (FS_DISPLAY == FS_GLOBAL) {
 		   	attron(A_REVERSE);
    		move (1, 1);
 			  printw ("Interval: %-4i sec   Alarms: Memory: %6dK  Swap: %6dK  Global: %6.2f %%",delay,mthresh,sthresh,thresh);
    		move (2, 1);
    		printw ("----------------------- FILE SYSTEMS ----------------------- -- PERCENT --   ");
 		   	move (3, 1);
 		   	printw ("DEVICE      MOUNT POINT       BSIZE   1KBLKS   AVAIL    USED   USED   PEAK   ");
 		   	attroff(A_REVERSE);
 		   	move (24, 0);
 		   	refresh();
			}
			else {
				if (FS_DISPLAY == FS_PARTITION) {
 		   		attron(A_REVERSE);
    			move (1, 1);
    			printw ("Interval: %-4i sec   Threshold: %6.2f %%                           Partition ",delay,thresh);
    			move (2, 1);
    			printw ("----------------------- FILE SYSTEMS ------------    ----- PERCENT ------    ");
		    	move (3, 1);
 		   		printw ("DEVICE      MOUNT POINT        TYPE    #    AVAIL    THRESH   USED   PEAK    ");
 			   	attroff(A_REVERSE);
 			   	move (24, 0);
 			   	refresh();
				}
			}
		}
		if (MODE != SHOW_MEMORY) {
		  if ((BKGD_MEM == 1) || (BKGD_SWAP == 1)) {
		  	main_mem = show_meminfo(QUIET);
			}
		}

  } /* while true */
} 	/* main */


/*
 * writetty
 * writes message "s" to user "u" 
 */
int 
writetty (u, s)
char *u, *s;
{

  FILE *port;
  char dev[128];

  while ((utm = getutent ()) != (struct utmp *) NULL)
  {
    if (strcmp (utm->ut_name, u) == 0)
    {
      strcpy (dev, "/dev/");
      strcat (dev, utm->ut_line);
      if ((port = fopen (dev, "w")) == (FILE *) NULL)
				continue;
      fputs (s, port);
      fputs ("\r\n", port);
      fclose (port);
    }
  }
  endutent ();
}

/*
 * SIGTSTP catcher.
 */
void
stop(void)
{
  /* Reset terminal. */
  printf(".................");
  ioctl(0, TCSETAF, &Savetty);
  fflush(stdout);
  /* raise(SIGTSTP); */
  ioctl(0, TCSETAF, &newtty);
	exit(0);
}

/*
 * Normal end of execution.
 */
void
end(void)
{
  clear();
  refresh();
  ioctl(0, TCSETAF, &Savetty);
	curs_set(1);                    /* Restore visible cursor */
	clear();
	exit(0);
}

void
chg_dcolor(void)
{
	if (COLOR_OK) {
		if (COLOR_DO == COLOR_YES) {
 			COLOR_DO = COLOR_NO;
			attrset(COLOR_PAIR(CLR_MONO));
			printf("%s%sGoing to monochrome display",tgoto(cm, 0, 23), clrtoeol);
		}
		else {
 			COLOR_DO = COLOR_YES;
			printf("%s%sGoing to color display",tgoto(cm, 0, 23), clrtoeol);
		}
		new_view = 1;
		new_mode = 1;
		new_color = 1;
	}
	else {
		printf("%s%sColor display is not supported",tgoto(cm, 0, 23), clrtoeol);
	}
 	fflush(stdout);     /* Flush buffered IO */
	sleep(1);
 	printf("%s%s",tgoto(cm, 0, 23), clrtoeol);
 	return;
}

void
chg_display(void)
{
	if (FS_DISPLAY == FS_GLOBAL) {
 		FS_DISPLAY = FS_PARTITION;
		printf("%s%sFS display changed to 'partition' status",tgoto(cm, 0, 23), clrtoeol);
	}
	else {
 		FS_DISPLAY = FS_GLOBAL;
		printf("%s%sFS display changed to 'global' status",tgoto(cm, 0, 23), clrtoeol);
	}
 	fflush(stdout);     /* Flush buffered IO */
	sleep(1);
	new_view = 1;
 	printf("%s%s",tgoto(cm, 0, 23), clrtoeol);
 	return;
}

void
chg_mode(void)
{
	if (THRESH_CHK == THRESH_G) {
 		THRESH_CHK = THRESH_P;
		printf("%s%sThreshold monitor set to Partition",tgoto(cm, 0, 23), clrtoeol);
	}
	else {
 		THRESH_CHK = THRESH_G;
		printf("%s%sThreshold monitor set to Global",tgoto(cm, 0, 23), clrtoeol);
	}
 	fflush(stdout);     /* Flush buffered IO */
	sleep(1);
	new_mode = 1;
 	printf("%s%s",tgoto(cm, 0, 23), clrtoeol);
 	return;
}

void
chg_sound(void)
{
	if (THRESH_SND == SOUND_OFF) {
 		THRESH_SND = SOUND_ON;
		printf("%s%sSound is now ON",tgoto(cm, 0, 23), clrtoeol);
	}
	else {
 		THRESH_SND = SOUND_OFF;
		printf("%s%sSound is now OFF",tgoto(cm, 0, 23), clrtoeol);
	}
 	fflush(stdout);     /* Flush buffered IO */
	sleep(1);
 	printf("%s%s",tgoto(cm, 0, 23), clrtoeol);
 	return;
}

void
set_global_thresh(void)
{
  int numinput;
  char line[BUFSIZ];
  char lin2[BUFSIZ];
  int i = 0;
  int r = 0;

	printf("%s%sGlobal Threshold: ",tgoto(cm, 0, 23), clrtoeol);
 	fflush(stdout);     /* Flush buffered IO */
 	fflush(stdin);			/* Not POSIX but ok */
 	i = 0;
 	do {
		read(STDIN_FILENO, &lin2[i], 1);
 	} 
 	while (lin2[i++] != '\n' && i < sizeof(lin2));
 	lin2[--i] = 0;
 	sscanf(lin2, "%d", &r);
	inthresh = atof(lin2);
	if ((inthresh > 0) && (inthresh <= 100)){
 		thresh = inthresh;
		printf("%s%sThreshold set to: %2.2f",tgoto(cm, 0, 23), clrtoeol,inthresh);
 		fflush(stdout);     /* Flush buffered IO */
		sleep(1);
 		attron(A_REVERSE);
 		move (1, 1);
 		printw ("Interval: %-4i sec   Threshold: %6.2f %%                                     ",delay,thresh);
 		attroff(A_REVERSE);
	}
	else {
		printf("%s%sInvalid threshold: %f",tgoto(cm, 0, 23), clrtoeol,inthresh);
 		fflush(stdout);     /* Flush buffered IO */
		sleep(1);
	}
}

void
set_mem_thresh(int mode)
{
  int numinput;
  char line[BUFSIZ];
  char lin2[BUFSIZ];
  int i = 0;
  int r = 0;

	printf("%s%sMemory Threshold: ",tgoto(cm, 0, 23), clrtoeol);
 	fflush(stdout);     /* Flush buffered IO */
 	fflush(stdin);			/* Not POSIX but ok */
 	i = 0;
 	do {
		read(STDIN_FILENO, &lin2[i], 1);
 	} 
 	while (lin2[i++] != '\n' && i < sizeof(lin2));
 	lin2[--i] = 0;
 	sscanf(lin2, "%d", &r);
	numinput = atoi(lin2);
	if ((numinput > 0) && (numinput <= 99000)){
		if (mode == BKGD) {
		  BKGD_MEM = 1;
		}
		mthresh = numinput;
		printf("%s%sThreshold set to: %dK",tgoto(cm, 0, 23), clrtoeol,numinput);
 		fflush(stdout);     /* Flush buffered IO */
		sleep(1);
	}
	else {
		printf("%s%sInvalid threshold: %d",tgoto(cm, 0, 23), clrtoeol,numinput);
 		fflush(stdout);     /* Flush buffered IO */
		sleep(1);
	}
}

void
set_swap_thresh(int mode)
{
  int numinput;
  char line[BUFSIZ];
  char lin2[BUFSIZ];
  int i = 0;
  int r = 0;

	printf("%s%sSwap Threshold: ",tgoto(cm, 0, 23), clrtoeol);
 	fflush(stdout);     /* Flush buffered IO */
 	fflush(stdin);			/* Not POSIX but ok */
 	i = 0;
 	do {
		read(STDIN_FILENO, &lin2[i], 1);
 	} 
 	while (lin2[i++] != '\n' && i < sizeof(lin2));
 	lin2[--i] = 0;
 	sscanf(lin2, "%d", &r);
	numinput = atoi(lin2);
	if ((numinput > 0) && (numinput <= 99000)) {
		if (mode == BKGD) {
			BKGD_SWAP = 1;
		}
		sthresh = numinput;
		printf("%s%sThreshold set to: %dK",tgoto(cm, 0, 23), clrtoeol,numinput);
 		fflush(stdout);     /* Flush buffered IO */
		sleep(1);
	}
	else {
		printf("%s%sInvalid threshold: %d",tgoto(cm, 0, 23), clrtoeol,numinput);
 		fflush(stdout);     /* Flush buffered IO */
		sleep(1);
	}
}

void
get_part(void)
{
  int numinput;
  char line[BUFSIZ];
  char lin2[BUFSIZ];
  int i = 0;
  int r = 0;

 	printf("%s%sPartition: ",tgoto(cm, 0, 23), clrtoeol);

 	fflush(stdout);     /* Flush buffered IO */
 	fflush(stdin);			/* Not POSIX but ok */

 	do {
 		read(STDIN_FILENO, &line[i], 1);
 	} 
 	while (line[i++] != '\n' && i < sizeof(line));
 	line[--i] = 0;
 	sscanf(line, "%d", &r);
 	numinput = atoi(line);
 	fflush(stdin);			/* Not POSIX but ok */
 	if (numinput <= pcount) {
   	ppart = numinput;
 		printf("%s%sThreshold: ",tgoto(cm, 20, 23), clrtoeol);
 		fflush(stdout);     /* Flush buffered IO */
 		fflush(stdin);			/* Not POSIX but ok */
 		i = 0;
 		do {
 			read(STDIN_FILENO, &lin2[i], 1);
 		} 
 		while (lin2[i++] != '\n' && i < sizeof(lin2));
 		lin2[--i] = 0;
 		sscanf(lin2, "%d", &r);
 		inthresh = atof(lin2);
 		if ((inthresh > 0) && (inthresh <= 100)){
   		pthresh = inthresh;
   		new_pthresh = 1;
 			printf("%s%sPartition %d set to: %2.2f",tgoto(cm, 0, 23), clrtoeol,ppart,inthresh);
 			fflush(stdout);     /* Flush buffered IO */
			sleep(1);
		}
		else {
 			printf("%s%sInvalid threshold: %f",tgoto(cm, 0, 23), clrtoeol,inthresh);
 			fflush(stdout);     /* Flush buffered IO */
			sleep(1);
		}
	}
	else {
 		printf("%s%sInvalid partition: %d",tgoto(cm, 0, 23), clrtoeol,numinput);
 		fflush(stdout);     /* Flush buffered IO */
		sleep(1);
	}
 	printf("%s%s",tgoto(cm, 0, 23), clrtoeol);
	return;
}

/*
 * Process keyboard input.  (Interactive mode)
 */
void
do_key(char c)
{
  int numinput;
  char line[BUFSIZ];
  char lin2[BUFSIZ];
  int i = 0;
  int r = 0;

  /*
   * First the commands which don't require a terminal mode switch.
   */
  if (c == 'q') {
	  end(); 
	}
  else if (c == 12) {
	  clear();
		return;
  }

  /*
   * Switch the terminal to normal mode.  
   */
  ioctl(0, TCSETA, &Savetty);

  /*
   * Handle the rest of the commands.
   */
  switch (c) {
  	case 'o':                  /* Toggle color on/off */
  		chg_dcolor();
  		ioctl(0, TCSETA, &Rawtty);
  		break;

  	case 'd':									 /* Change header for other fs info */
			chg_display();
    	ioctl(0, TCSETA, &Rawtty); 
			break;

    case 'i':                  /* Set the update interval */
	  	printf("%s%sDelay between updates: ",tgoto(cm, 0, 23), clrtoeol);

    	fflush(stdout);     /* Flush buffered IO */
    	fflush(stdin);			/* Not POSIX but ok */

      do {
	  		read(STDIN_FILENO, &line[i], 1);
    	} 
    	while (line[i++] != '\n' && i < sizeof(line));
    	line[--i] = 0;
    	sscanf(line, "%d", &r);
	  	numinput = (int) line;
	    if (numinput != -1) {
	    	Sleeptime = atof(line);
	    	delay = atoi(line);
			}
    	printf("%s%s",tgoto(cm, 0, 23), clrtoeol);
    	ioctl(0, TCSETA, &Rawtty); 
    	attron(A_REVERSE);
    	move (1, 1);
    	printw ("Interval: %-4i sec   Threshold: %6.2f %%                                     ",delay,thresh);
    	attroff(A_REVERSE);
			break;

    case 't':                  /* Set the disk space threshold level */
	  	printf("%s%sThreshold (G)lobal / (P)artition / (T)oggle / (M)emory / (S)wap: ",tgoto(cm, 0, 23), clrtoeol);

    	fflush(stdout);     /* Flush buffered IO */
    	fflush(stdin);			/* Not POSIX but ok */

    	do {
	  		read(STDIN_FILENO, &line[i], 1);
    	} 
    	while (line[i++] != '\n' && i < sizeof(line));
    	line[--i] = 0;
    	sscanf(line, "%s", &r);
    	if ((line[0] == 'g') || (line[0] == 'G')) {
    		set_global_thresh();
			}
    	else {
    		if ((line[0] == 'p') || (line[0] == 'P')) {
    			get_part();
				}
				else {
    			if ((line[0] == 'm') || (line[0] == 'M')) {
    				set_mem_thresh(FRGD);
    			}
    			else {
    				if ((line[0] == 's') || (line[0] == 'S')) {
    					set_swap_thresh(FRGD);
						}
						else {
    					if ((line[0] == 't') || (line[0] == 'T')) {
    						chg_mode();
							} 
						} 	/* Swap else */
					}   	/* Memory else */
				}     	/* Partition else */
			}       	/* Global else */
    	printf("%s%s",tgoto(cm, 0, 23), clrtoeol);
    	ioctl(0, TCSETA, &Rawtty); 
			break;

		case 'p':                  /* Set partition threshold */ 
			get_part();
    	ioctl(0, TCSETA, &Rawtty); 
			break;

		case 's':                  /* Toggle between global/partitions */
			chg_mode();
    	ioctl(0, TCSETA, &Rawtty); 
			break;

		case 'm':                  /* Display memory stats */
		  MODE = SHOW_MEMORY;
		  BKGD_MEM = 0;
		  BKGD_SWAP = 0;
			ioctl(0, TCSETA, &Rawtty);
		  break;

		case 'c':                  /* Clear current sub-display */
			MODE = SHOW_NOTHING;
			ioctl(0, TCSETA, &Rawtty);
			break;

		case 'n':                  /* Display network interface stats */
			MODE = SHOW_NET;
			ioctl(0, TCSETA, &Rawtty);
			break;

		case 'v':                  /* Show version information */
			MODE = SHOW_VER;
			ioctl(0, TCSETA, &Rawtty);
			break;

		case 'w':                  /* Toggle sound warnings on/off */
			chg_sound();
			ioctl(0, TCSETA, &Rawtty);
			break;	

		case 'b':                  /* Toggle background mode */
	  	printf("%s%sBackground (M)emory / (S)wap: ",tgoto(cm, 0, 23), clrtoeol);

    	fflush(stdout);     /* Flush buffered IO */
    	fflush(stdin);			/* Not POSIX but ok */

    	do {
	  		read(STDIN_FILENO, &line[i], 1);
    	} 
    	while (line[i++] != '\n' && i < sizeof(line));
    	line[--i] = 0;
    	sscanf(line, "%s", &r);
    	if ((line[0] == 'm') || (line[0] == 'M')) {
    		set_mem_thresh(BKGD);
    	}
    	else {
  			if ((line[0] == 's') || (line[0] == 'S')) {
  				set_swap_thresh(BKGD);
				}
    	}
    	printf("%s%s",tgoto(cm, 0, 23), clrtoeol);
			ioctl(0, TCSETA, &Rawtty);
			break;


    case 'h':                  /* Display help information */
    case '?':
    	MODE = SHOW_HELP;
    	/* HELP_SCREEN; */
			ioctl(0, TCSETA, &Rawtty);
			/* (void) getchar(); */
			break;
    	
    default:                     /* Default - do nothing */
    	ioctl(0, TCSETA, &Rawtty); /* Go back to Raw mode */
    	return;
	}
}


/* ---------- Memory information ---------- */


unsigned
show_meminfo(int mode)
{
  char memory[1024];
  static int fd;
  unsigned int main_mem, used_mem, free_mem, shared_mem, buf_mem;
  unsigned int swap_mem, used_swap, free_swap;
  unsigned int pg_in, pg_out, swp_in, swp_out;

  fd = open(MEM_FILE, O_RDONLY, 0);
  if (fd == -1) {
    printf("Couldn't open %s",MEM_FILE); 
    end();
  }
  read(fd, memory, sizeof(memory) - 1);
  close(fd);
  sscanf(memory, "%*s %*s %*s %*s %*s %*s %u %u %u %u %u %*s %u %u %u",
	 &main_mem, &used_mem, &free_mem, &shared_mem, &buf_mem,
	 &swap_mem, &used_swap, &free_swap);

  fd = open(STAT_FILE, O_RDONLY, 0);
  if (fd == -1) {
    printf("Couldn't open %s",STAT_FILE);
    end();
  }
  read(fd, memory, sizeof(memory) - 1);
  close(fd);
  sscanf(memory, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %u %u %*s %u %u",
  	&pg_in, &pg_out, &swp_in, &swp_out);
	if ((mthresh > (free_mem/1024)) || (sthresh > (free_swap/1024))) {
		attron(A_REVERSE);
	  if (mthresh > (free_mem/1024)) {
			move (0,50);
    	printw ("Memory");
    	if (THRESH_SND == SOUND_ON) {
    		beep();
			}
		}
		if (sthresh > (free_swap/1024)) {
			move (0,58);
 	   	printw ("Swap");
    	if (THRESH_SND == SOUND_ON) {
    		beep();
			}
		}
		if (mthresh <= free_mem/1024) {
			move (0,50);
			printw ("      ");
		}
		if (sthresh <= free_swap/1024) {
			move (0,58);
			printw ("    ");
		}
		attroff(A_REVERSE);
   	move (24,0);
   	refresh();
	}
	if (mode == VERBOSE) {
		move (17,0);
		clrtobot();
		if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
			attrset(COLOR_PAIR(CLR_NORMAL));
		}
		attron(A_REVERSE);
		move (17,0);
		printw("Memory Information:                                    Threshold: %6dK     ",mthresh);
		attroff(A_REVERSE);
		move (18,0);
		if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
			attrset(COLOR_PAIR(CLR_MEM));
		}
  	printw("Avg: %5dK   Used: %5dK   Free: %5dK   Shared: %5dK   Buffers: %5dK",
	  	main_mem / 1024, used_mem / 1024, free_mem / 1024, 
	  	shared_mem / 1024, buf_mem / 1024);
		move (19,0);
		if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
			attrset(COLOR_PAIR(CLR_NORMAL));
		}
		attron(A_REVERSE);
		printw("Swap / Paging Information:                             Threshold: %6dK     ",sthresh);
		attroff(A_REVERSE);
		move (20,0);
		if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
			attrset(COLOR_PAIR(CLR_MEM));
		}
  	printw("Avg: %5dK   Used: %5dK   Free: %5dK",
	  	swap_mem / 1024, used_swap / 1024, free_swap / 1024);
		move (21,0);
		printw("Swap In: %6d   Swap Out: %6d",swp_in,swp_out);
		move (22,0);
		printw("Page In: %6d   Page Out: %6d",pg_in,pg_out);
		if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
			attrset(COLOR_PAIR(CLR_NORMAL));
		}
		clrtobot();
		refresh(); 
	}
  return(main_mem);
}

/* ---------- Session handling --------- */

char *sprint_session(void) 
{
  struct utmp utmpstruct;
  int upminutes, uphours, updays;
  static int utmp_fd = -1;
  int nread, pos;
  time_t realseconds;
  int numuser;
  double uptime_secs, idle_secs;


	/* Get the current time */
  realseconds = time(NULL);
  /* realtime = localtime(&realseconds); */
 
	/* read and calculate the amount of uptime */
	elapsed = difftime(realseconds,session_start);
  updays = (int) elapsed / (60*60*24);
  strcat (sess, "   ");
  pos = 0;
  pos += 1;
  if (updays)
    pos += sprintf(sess + pos, "%d day%s, ", updays, (updays != 1) ? "s" : "");
  upminutes = (int) elapsed / 60;
  uphours = upminutes / 60;
  uphours = uphours % 24;
  upminutes = upminutes % 60;
  if(uphours)
    pos += sprintf(sess + pos, "%2d:%02d %s", uphours,upminutes,&lname);
  else
    pos += sprintf(sess + pos, "%d min %s", upminutes,&lname);

  pos += sprintf(sess + pos, " ");
  /* sprintf(sess, "elapsed: %10d ",elapsed); */

  return sess;
}

/* ---------- Uptime handling ---------- */

char *sprint_uptime(void) 
{
  struct utmp utmpstruct;
  int upminutes, uphours, updays;
  static int utmp_fd = -1;
  int nread, pos;
  struct tm *realtime;
  time_t realseconds;
  int numuser;
  double uptime_secs, idle_secs;

	/* Get the current time */

  time(&realseconds);
  realtime = localtime(&realseconds);
  pos = sprintf(upt, " %2d:%02d%s  ",
		realtime->tm_hour%12 ? realtime->tm_hour%12 : 12,
		realtime->tm_min, realtime->tm_hour > 11 ? "pm" : "am");

	/* read and calculate the amount of uptime */

  uptime(&uptime_secs, &idle_secs);

  updays = (int) uptime_secs / (60*60*24);
  strcat (upt, "up ");
  pos += 3;
  if (updays)
    pos += sprintf(upt + pos, "%d day%s, ", updays, (updays != 1) ? "s" : "");
  upminutes = (int) uptime_secs / 60;
  uphours = upminutes / 60;
  uphours = uphours % 24;
  upminutes = upminutes % 60;
  if(uphours)
    pos += sprintf(upt + pos, "%2d:%02d, ", uphours, upminutes);
  else
    pos += sprintf(upt + pos, "%d min, ", upminutes);

	/* count the number of users */

  if (utmp_fd < 0) {
    utmp_fd = open(UTMP_FILE, O_RDONLY);
    if (utmp_fd < 0) {
      perror("open " UTMP_FILE);
      exit(1);
    }
  }

  lseek(utmp_fd, 0L, SEEK_SET);

  numuser = 0;
  while (1) {
    nread = read(utmp_fd, &utmpstruct, sizeof utmpstruct);
    if (nread == 0)
      break;
    if (nread < 0) {
      perror("read " UTMP_FILE);
      exit(1);
    }
    if (nread != sizeof utmpstruct) {
      fprintf(stderr, "bad data in " UTMP_FILE);
      exit(1);
    }
    if ((utmpstruct.ut_type == USER_PROCESS) &&
			 (utmpstruct.ut_name[0] != '\0'))
       numuser++;
  }

  pos += sprintf(upt + pos, "%2d user%s, ", numuser, numuser == 1 ? "" : "s");

  loadavg(&av[0], &av[1], &av[2]);

  pos += sprintf(upt + pos, " load avg: %.2f, %.2f, %.2f",
		 av[0], av[1], av[2]);

  return upt;
}


void loadavg(double *av1, double *av5, double *av15)
{
  int n;

  char buff[80];
  static int fd = -1;

  if (fd < 0) {
		if ((fd = open(LOAD_FILE, O_RDONLY)) < 0) {
	    perror(LOAD_FILE);
	    exit(1);
		}
  }

  lseek(fd, 0L, SEEK_SET);
  n = read(fd, buff, sizeof buff - 1);
  if (n < 0) {
		perror(LOAD_FILE);
		exit(1);
  }
  buff[n] = '\0';

  if (sscanf(buff, "%lf %lf %lf", av1, av5, av15) < 3) {
	  fprintf(stderr, "bad data in " LOAD_FILE "\n");
	  exit(1);
  }

  return;
}


void uptime(double *uptime_secs, double *idle_secs)
{
   int n;
   char buff[80];
   static int fd = -1;

   if (fd < 0) {
	   if ((fd = open(UPTIME_FILE, O_RDONLY)) < 0) {
	    	perror(UPTIME_FILE);
	    	exit(1);
		 }
   }

   lseek(fd, 0L, SEEK_SET);
   n = read(fd, buff, sizeof buff - 1);
   if (n < 0) {
	   perror(UPTIME_FILE);
		 exit(1);
   }
   buff[n] = '\0';

   if (sscanf(buff, "%lf %lf", uptime_secs, idle_secs) < 2) {
		 fprintf(stderr, "bad data in " UPTIME_FILE "\n");
		 exit(1);
   }

   return;
}




/*     ---------- Network Interface Info ------------     */


static void if_getstats(char *ifname, struct interface *ife)
{
   FILE *f=fopen(NETDEV_FILE,"r");
   char buf[256];
   char *bp;
   if(f==NULL)
  	 return;
   while(fgets(buf,255,f))
   {
  	 bp=buf;
  	 while(*bp&&isspace(*bp))
  		 bp++;
  	 if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
  	 {
 		    (int) bp = strchr(bp,':');
 		    bp++;
 		    sscanf(bp,"%d %d %d %d %d %d %d %d %d %d %d",
 			    &ife->stats.rx_packets,
 		    	&ife->stats.rx_errors,
 			    &ife->stats.rx_dropped,
 			    &ife->stats.rx_fifo_errors,
 			    &ife->stats.rx_frame_errors,
 			
 			    &ife->stats.tx_packets,
 			    &ife->stats.tx_errors,
 			    &ife->stats.tx_dropped,
 			    &ife->stats.tx_fifo_errors,
 			    &ife->stats.collisions,
 			
 			    &ife->stats.tx_carrier_errors
 		    );
 				fclose(f);
 				return;
  		}
  	}
  	fclose(f);  /* NETDEV_FILE */
}

static void
ife_print(struct interface *ptr)
{
  if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
	  attrset(COLOR_PAIR(CLR_NET));
	}
  printw("%-5.5s ", ptr->name);
  printw("%5d %3d ", ptr->mtu, ptr->metric);
  /* If needed, display the interface statistics. */
  printw("%6u %6u %6u %6u ",
	  ptr->stats.rx_packets, ptr->stats.rx_errors,
	  ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors);
  printw("%6u %6u %6u %6u ",
	  ptr->stats.tx_packets, ptr->stats.tx_errors,
	  ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors);
  if (ptr->flags == 0) printw("[NO FLAGS]");
  if (ptr->flags & IFF_ALLMULTI) printw("A");
  if (ptr->flags & IFF_BROADCAST) printw("B");
  if (ptr->flags & IFF_DEBUG) printw("D");
  if (ptr->flags & IFF_LOOPBACK) printw("L");
  if (ptr->flags & IFF_PROMISC) printw("M");
  if (ptr->flags & IFF_NOTRAILERS) printw("N");
  if (ptr->flags & IFF_NOARP) printw("O");
  if (ptr->flags & IFF_POINTOPOINT) printw("P");
  if (ptr->flags & IFF_RUNNING) printw("R");
  if (ptr->flags & IFF_UP) printw("U");
  printw("\n");
}

/* Fetch the inteface configuration from the kernel. */
static int
if_fetch(char *ifname, struct interface *ife)
{
  struct ifreq ifr;
  
  memset((char *) ife, 0, sizeof(struct interface));
  strcpy(ife->name, ifname);
  
  strcpy(ifr.ifr_name, ifname);
  if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
		 fprintf(stderr, "SIOCGIFFLAGS: %s\n", strerror(errno));
		 return(-1);
  }
  ife->flags = ifr.ifr_flags;
  
  strcpy(ifr.ifr_name, ifname);
  if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) {
		 memset(&ife->addr, 0, sizeof(struct sockaddr));
  }
  else 
 	  ife->addr = ifr.ifr_addr;
  
  strcpy(ifr.ifr_name, ifname);
  if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) {
		 memset(&ife->hwaddr, 0, sizeof(struct sockaddr));
  }
  else 
 	  ife->hwaddr = ifr.ifr_addr;
  
  strcpy(ifr.ifr_name, ifname);
  if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) {
		ife->metric = 0;
  } 
  else 
 	  ife->metric = ifr.ifr_metric;
  
  strcpy(ifr.ifr_name, ifname);
  if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) {
		ife->mtu = 0;
  }
  else 
   	ife->mtu = ifr.ifr_mtu;
  
  strcpy(ifr.ifr_name, ifname);
  if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) {
		memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
  } 
  else 
  	ife->dstaddr = ifr.ifr_dstaddr;
  
  strcpy(ifr.ifr_name, ifname);
  if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) {
		memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
  } 
  else 
  	ife->broadaddr = ifr.ifr_broadaddr;
  
  strcpy(ifr.ifr_name, ifname);
  if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) {
		memset(&ife->netmask, 0, sizeof(struct sockaddr));
  } 
  else {
		memcpy(ife->netmask.sa_data, &ifr.ifr_data, sizeof(struct sockaddr));
  }
    
  if_getstats(ifname,ife);
  return(0);
}

static int
iface_info(void)
{
  char buff[1024];
  struct interface ife;
  struct ifconf ifc;
  struct ifreq *ifr;
  int i;
  
  /* Create a channel to the NET kernel. */
  if ((skfd = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
		perror("socket");
		return(E_READ);
  }
  
  ifc.ifc_len = sizeof(buff);
  ifc.ifc_buf = buff;
  if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
		perror("SIOCGIFCONF");
		return(E_IOCTL);
  }

  if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
	  attrset(COLOR_PAIR(CLR_NORMAL));
	}
  attron(A_REVERSE);
	move (17,0);
  printw("Kernel Interface table:                                                       ");
  move (18,0);
  printw("Iface   MTU Met  RX-OK RX-ERR RX-DRP RX-OVR  TX-OK TX-ERR TX-DRP TX-OVR Flags \n");
  attroff(A_REVERSE);
  
  ifr = ifc.ifc_req;
  for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
		if (if_fetch(ifr->ifr_name, &ife) < 0) {
			fprintf(stderr, "%s: unknown interface.\n", ifr->ifr_name);
		}
    
		if (((ife.flags & IFF_UP) == 0)) continue;
		ife_print(&ife);
		refresh();
  }
  if ((COLOR_OK) && (COLOR_DO == COLOR_YES))  {
	  attrset(COLOR_PAIR(CLR_NORMAL));
	}
  return(0);
}
/* EOF - vixen */
