/*
 *
 * procstatd - Copyright (c) 1999 by Robert G. Brown, rgb@phy.duke.edu
 *         GPL version 2b (b for beverage) granted.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * procstatd - A daemon to extract statistics from /proc/stat and publish them
 *         on demand via a socket connection or broadcast.
 */

/* this module by John B. Pormann, jpormann@ee.duke.edu */

/* this may not be useful to anyone else but me... but that's part of */
/* open-source software too!!  :)  Our department uses an auto-mount  */
/* daemon which occassionally leaves some of our cluster machines out */
/* in the cold - you can ping them and telnet to them, even connect   */
/* to the procstatd - but you cannot actually *use* the machines as   */
/* you cannot get to your home directory.  So this module is designed */
/* to effectively do "ls /home/<dir-list>" on a bunch of should-be    */
/* mounted directories, then returns the number of good and bad       */
/* connections that it found.                                         */

/* the idea is to explicitly look at /home/<dir-list> and make sure   */
/* that this machine can see those directories.  In our department,   */
/* we have had problems with machine being up (ping- and telnet-able) */
/* but not able to access /home/shiva, hence they cannot mount users  */
/* home directories and are effectively off-line.  Hopefully we can   */
/* detect this and report it back to the system, and correct it, so   */
/* that users know if a machine is "really" on-line or not.           */

/* NOTE: I've since taken out the 'ls /home/...' stuff and just do    */
/* a search for the amd daemon, then report the PID number if found   */
/* or -1 if not found                                                 */

#include "procstatd.h"
#include <dirent.h>

/* define the file servers to scan here */
const int num_filesys = 4;
const char* filesys[] = {
	"/home/shiva", "/home/emagserver", 
	"/home/emagserver2", "/home/emagserver3"
};

/* we'll keep the pid around, just in case */
/* but we really just use the stat_fd[FS_CONNECT] file pointer */
static int amd_pid = 0;
static char amd_dir[256];

void init_filestuff()
{
 int i;
 int num_good = 0, num_bad = 0;
 DIR* dp;
 struct dirent* procdir;
 char ftmp[128],data[1024];

#if defined(__XXYYZZ__)
 for(i=0;i<num_filesys;i++) {
	dp = opendir( filesys[i] );
	if( dp == NULL ) {
		num_bad++;
	} else {
		num_good++;
		closedir( dp );
	}
 }
#endif

 /* try to find an amd process */
 stat_fd[FS_CONNECT] = NULL;
 dp = opendir( "/proc" );
 while( 1 ) {
   procdir = readdir( dp );
   if( procdir == NULL ) {
	break;
   }

   if( (procdir->d_name[0]>='0') && (procdir->d_name[0]<='9') ) {
	/* assume this is a PID */
	sprintf( ftmp, "/proc/%s/status", procdir->d_name );
	stat_fd[FS_CONNECT] = fopen( ftmp, "r" );
	if( stat_fd[FS_CONNECT] != NULL ) {
		/* grab first line: command name */
		fgets( data, 1024, stat_fd[FS_CONNECT] );
		/* scan ahead to the colon in "Name:" */
		i = 0;
		while( data[i] != ':' ) {
			i++;
		}
		i++;
		while( (data[i]=='\t') || (data[i]==' ') ) {
			i++;
		}
		/* now check for 'a' 'm' 'd' 0 */
		if( (data[i]=='a') && (data[i+1]=='m') && (data[i+2]=='d')
		    && (data[i+3]==10) && (data[i+4]==0) ) {
			/* found!! */
			amd_pid = atoi( procdir->d_name );
			sprintf( amd_dir, "/proc/%i", amd_pid );
			break;
		}
		fclose( stat_fd[FS_CONNECT] );
		stat_fd[FS_CONNECT] = NULL;
	}
   }
 }
 closedir( dp );

#if defined(__XXYYZZ__)
 sprintf( stats[FS_GOODCNX].name, "fs_goodcnx" );
 stats[FS_GOODCNX].source = FS_CONNECT;
 stats[FS_GOODCNX].avail = 1;
 stats[FS_GOODCNX].current = num_good;

 sprintf( stats[FS_BADCNX].name, "fs_badcnx" );
 stats[FS_BADCNX].source = FS_CONNECT;
 stats[FS_BADCNX].avail = 1;
 stats[FS_BADCNX].current = num_bad;
#endif

 sprintf( stats[FS_AMDSTAT].name, "fs_amdstat" );
 stats[FS_AMDSTAT].source = FS_CONNECT;
 stats[FS_AMDSTAT].avail = 1;
 stats[FS_AMDSTAT].current = amd_pid;
}

void get_filestuff()
{
 int i;
 int num_good = 0, num_bad = 0;
 DIR* dp;

#if defined(__XXYYZZ__)
 for(i=0;i<num_filesys;i++) {
	dp = opendir( filesys[i] );
	if( dp == NULL ) {
		num_bad++;
	} else {
		num_good++;
		closedir( dp );
	}
 }

 /* we could rewind() the stream, but that returns no error */
 /* so we'll fseek() instead */
 if( stat_fd[FS_CONNECT] != NULL ) {
	i = fseek( stat_fd[FS_CONNECT], 0, SEEK_SET );
	if( i < 0 ) {
		amd_pid = -1;
	}
 }

 stats[FS_GOODCNX].current = num_good;
 stats[FS_BADCNX].current = num_bad;
#endif

 dp = opendir( amd_dir );
 if( dp == NULL ) {
    stats[FS_AMDSTAT].current = 0;
 } else {
    /* could do: stats[FS_AMDSTAT].current = amd_pid; */
    stats[FS_AMDSTAT].current = 1;
 }
 closedir( dp );

}

void eval_filestuff()
{

#if defined(__XXYYZZ__)
  stats[FS_GOODCNX].rate = stats[FS_GOODCNX].current;
  if(stats[FS_GOODCNX].rate < 0.0) stats[FS_GOODCNX].rate = 0.0;
  stats[FS_BADCNX].rate = stats[FS_BADCNX].current;
  if(stats[FS_BADCNX].rate < 0.0) stats[FS_BADCNX].rate = 0.0;
#endif

  stats[FS_AMDSTAT].rate = stats[FS_AMDSTAT].current;
}

