#include "os/Solaris.h"

/* Make sure /proc is mounted */
char* OS_initialize(){
  struct statvfs svfs;

  static char* no_proc = "/proc unavailable";
  if( statvfs("/proc", &svfs) == -1 ){
    return no_proc;
  }

  return NULL;
}


/* FIXME we should get minimum info like process ID and ownership from
   file stat-- does this work for IOCTL-proc? Does it for FS-proc? It
   does on linux... */
#include <sys/types.h>
void OS_get_table(){
  DIR *procdir;
  char p[sizeof(struct dirent) + 1024] ;
  struct dirent *procdirp = (struct dirent *)p;
  int psdata;
  char pathbuf[MAXPATHLEN];
  DIR *procdirlwp;
  struct dirent *procdirlwpp;
  char pathbuflwp[MAXPATHLEN];


#if defined(PROC_FS)
  struct psinfo psbuf;
#else
  struct prpsinfo psbuf;
#endif
  
  /* variables to hold some values for bless_into_proc */
  char state[20]; 
  char pctcpu[7];
  int numthr;
  char pctmem[7];

/* MR: quick hack for different readdir_r versions */ 
#if defined(_POSIX_PTHREAD_SEMANTICS)
 struct dirent *procdirp_r;
#endif
 
  if( (procdir = opendir( "/proc" )) == NULL ) return;
  
#if defined(_POSIX_PTHREAD_SEMANTICS)
  while( readdir_r(procdir, procdirp, &procdirp_r ) == 0 && procdirp_r != NULL ){
#else
  while( readdir_r(procdir, procdirp ) != NULL ){
#endif
    
    /* Only look at this file if it's a proc id; that is, all numbers */
    if( strtok(procdirp->d_name, "0123456789") != NULL ){ continue; }
      
    /* Construct path of the form /proc/proc_number */
    strcpy( pathbuf, "/proc/"); 
    strcat( pathbuf, procdirp->d_name );
    strcpy( pathbuflwp, pathbuf);
    strcat( pathbuflwp, "/lwp/");
    if( (procdirlwp = opendir( pathbuflwp )) != NULL ){
      numthr = 0;
      while( (procdirlwpp = readdir(procdirlwp)) != NULL ){
      numthr++;
      }
      closedir(procdirlwp);
    }
    numthr = numthr - 2;

      
#if defined(PROC_FS)
    strcat( pathbuf, "/psinfo" ); /* Solaris 2.6 has process info here */
#endif
      
    if( (psdata = open( pathbuf, O_RDONLY )) == -1 ) continue;
	
#if defined(PROC_FS)
    read(psdata, (void *) &psbuf, sizeof(struct psinfo) );
#else
    if( ioctl(psdata, PIOCPSINFO, &psbuf) == -1 ) continue; 
#endif
    close(psdata);

    /* translate process state */
#if defined(PROC_FS)
    switch( psbuf.pr_lwp.pr_state )
#else
    switch( psbuf.pr_state)
#endif
      {
      case SSLEEP: 
	strcpy(state, SLEEP);
	break;
      case SRUN:
	strcpy(state, RUN);
	break;
      case SZOMB:
	strcpy(state, ZOMBIE);
	break;
      case SSTOP:
	strcpy(state, STOP);
	break;
      case SIDL:
	strcpy(state, IDLE);
	break;
      case SONPROC:
	strcpy(state, ONPROC);
	break;
      }

    /* These seem to be 2 bytes, 1st byte int part, 2nd byte fractional */
    /* Perl can handle stringy numbers of the form 1.5 */
    sprintf( pctcpu,  "%5.2f%", ((double)psbuf.pr_pctcpu)/0x8000*100  );
    sprintf( pctmem,  "%5.2f%", ((double)psbuf.pr_pctmem)/0x8000*100 );
    
    bless_into_proc( Format,           
		     Fields,
		     
		     psbuf.pr_uid,           /* uid */
		     psbuf.pr_gid,           /* gid */
		     psbuf.pr_euid,          /* euid */
		     psbuf.pr_egid,          /* egid */
		     psbuf.pr_pid,           /* pid */
		     psbuf.pr_ppid,          /* ppid */
#if defined(PROC_FS)
		     psbuf.pr_pgid,          /* pgrp */ 
#else
		     psbuf.pr_pgrp,          /* pgrp */ 
#endif
		     psbuf.pr_sid,           /* sess */
#if defined(PROC_FS)
		     psbuf.pr_lwp.pr_pri,    /* priority */   
		     psbuf.pr_lwp.pr_nice,   /* nice */
#else
		     psbuf.pr_pri,           /* priority */   
		     psbuf.pr_nice,          /* nice */
#endif
		     psbuf.pr_ttydev,        /* ttynum */
		     psbuf.pr_flag,          /* flags */
		     psbuf.pr_time.tv_sec,   /* time */
		     psbuf.pr_ctime.tv_sec,  /* ctime */
#if defined(PROC_FS)
		     psbuf.pr_time.tv_nsec,   /* time nanosec */
		     psbuf.pr_ctime.tv_nsec,  /* ctime nanosec */
		     psbuf.pr_size * 1024,    /* size (bytes) */
		     psbuf.pr_rssize * 1024,  /* rss (bytes)  */
		     psbuf.pr_lwp.pr_wchan,   /* wchan */ 
#else
		     psbuf.pr_bysize,        /* size (bytes) */
		     psbuf.pr_byrssize,      /* rss (bytes)  */
		     psbuf.pr_wchan,         /* wchan */
#endif

		     psbuf.pr_fname,         /* fname */
		     psbuf.pr_start.tv_sec,  /* start */
		     pctcpu,                 /* pctcpu */
		     state,                  /* state */
#if defined(PROC_FS)
		     psbuf.pr_lwp.pr_onpro,  /* on which processor */
#endif
		     pctmem,                 /* pctmem */
		     psbuf.pr_psargs,        /* cmndline */ 
		     numthr                  /* numthr */ 
		    );
    
  }
  closedir(procdir);
}